お世話になります。
以前どこかのサイトで見た、Cで書かれた、日付から曜日を取得する関数を、C++風に
リファクタリングして、日付から金曜日の日付をコンテナに代入していく関数を作ってい
ます、
コンテナへの値の代入は上手く、動いているのですが、コンテナの値が、取得できない原
因が分かりません、ご教示お願いします。また、あえて汎用化するまでも、無いとは思う
のですが、
templateにできるなら、その実装も、お願いできないでしょうか。
宜しくお願いします。
原因の推測:
for_eachディレクティブに、引数を食わせて、第三引数の関数に、()演算子を、オーバー
ロードさせて、実行しているのですが、この()演算子が、他に影響を与えているような気
がします。また、このようなクラス名に対して、()演算子をオーバーロードさせるという
使い方は間違っている気もするのですが。
環境:WinXP SP2/VS2005 MFC
//実装
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class TransFormFriday
{
int y, m, d;
vector<int> vFriday;
public:
TransFormFriday() : y(0), m(0), d(0){}
void operator()( const int& ymd )
{
y = ymd / 10000;
m = ymd % 10000 / 100;
d = ymd % 100;
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
if( ( ( y + y/4 - y/100 + y/400 + t[ m - 1 ] + d) % 7 ) == 5 ) {
cout << ymd << endl;
vFriday.push_back( ymd );
}
}
vector<int>& GetFriDay(){ return vFriday; };
};
int main()
{
vector<int>vec;
vec.push_back(20080701);
vec.push_back(20080704);
vec.push_back(20080705);
vec.push_back(20080706);
vec.push_back(20080707);
vec.push_back(20080708);
vec.push_back(20080711);
vec.push_back(20080712);
vec.push_back(20080713);
vec.push_back(20080714);
vec.push_back(20080715);
vec.push_back(20080719);
vec.push_back(20080720);
vec.push_back(20080721);
vec.push_back(20080722);
vec.push_back(20080725);
vec.push_back(20080726);
vec.push_back(20080727);
vec.push_back(20080728);
vec.push_back(20080729);
for_each( vec.begin(), vec.end(), TransFormFriday() );
TransFormFriday tff;
tff.GetFriDay();
vector<int>::iterator it;
it = tff.GetFriDay().begin(); //ここで値が取れない
while( it < tff.GetFriDay().end() ) {
cout << *it << endl;
it++;
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
struct IsNotFriday {
bool operator()(int ymd ) const {
int y = ymd / 10000;
int m = ymd % 10000 / 100;
int d = ymd % 100;
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return ( ( y + y/4 - y/100 + y/400 + t[ m - 1 ] + d) % 7 ) != 5;
}
};
int main() {
int date[20] = {
20080701, 20080704, 20080705, 20080706, 20080707,
20080708, 20080711, 20080712, 20080713, 20080714,
20080715, 20080719, 20080720, 20080721, 20080722,
20080725, 20080726, 20080727, 20080728, 20080729,
};
remove_copy_if(date, date+20, ostream_iterator<int>(cout,\n), IsNotFriday
() );
}
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class TransFormFriday
{
int y, m, d;
vector<int> vFriday;
public:
TransFormFriday() : y(0), m(0), d(0){}
void operator()( const int& ymd )
{
y = ymd / 10000;
m = ymd % 10000 / 100;
d = ymd % 100;
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
if( ( ( y + y/4 - y/100 + y/400 + t[ m - 1 ] + d) % 7 ) == 5 ) {
cout << ymd << endl;
vFriday.push_back( ymd );
}
}
vector<int>& GetFriDay(){ return vFriday; };
};
int main()
{
vector<int>vec;
vec.push_back(20080701);
vec.push_back(20080704);
vec.push_back(20080705);
vec.push_back(20080706);
vec.push_back(20080707);
vec.push_back(20080708);
vec.push_back(20080711);
vec.push_back(20080712);
vec.push_back(20080713);
vec.push_back(20080714);
vec.push_back(20080715);
vec.push_back(20080719);
vec.push_back(20080720);
vec.push_back(20080721);
vec.push_back(20080722);
vec.push_back(20080725);
vec.push_back(20080726);
vec.push_back(20080727);
vec.push_back(20080728);
vec.push_back(20080729);
// 正しい使い方
TransFormFriday tff;
for_each( vec.begin(), vec.end(), tff );
for ( vector<int>::iterator it = tff.GetFriDay().begin();
it != tff.GetFriDay().end(); ++it ) {
cout << *it << endl;
}
}
とまぁそゆわけで:
> for_eachディレクティブに、引数を食わせて、第三引数の関数に、()演算子を、
> オーバーロードさせて、実行しているのですが、この()演算子が、他に影響を
> 与えているような気がします。また、このようなクラス名に対して、
> ()演算子をオーバーロードさせるという使い方は間違っている気もするのですが。
っていう原因の推測は大間違い。
使い方がヘンなだけ。
# επιστημηさんの書かれている通り。
> for_each( vec.begin(), vec.end(), TransFormFriday() );
上では、TransFormFriday型の名前のない一時変数を引数に渡していることは大丈夫です
か。
> TransFormFriday tff;
> tff.GetFriDay();
そして、見ての通り、tffは生成後、一度もoperator()を呼ばれていないです。
ちなみに、自分でTransFormFriday::operator()を呼び出すとすれば、
tff(); TransFormFriday()();
などの書き方になります。
# 本質的なことではありませんが、[transform](変形/変換する)はあくまでこれが
# 一単語であって、[trans]+[form]という二単語ではありませんので
# (語源としてはそういう意味なんだとは思いますが)、Fの大文字にちょっと違和感が。
επιστημη さんBanさんお世話になります
早速ですが
επιστημη さんが最初に示してくださった、remove_copy_ifのパターンですが
コンテナにコピーするには、こんな使い方でいいでしょうか?
int main() {
int date[20] = {
20080701, 20080704, 20080705, 20080706, 20080707,
20080708, 20080711, 20080712, 20080713, 20080714,
20080715, 20080719, 20080720, 20080721, 20080722,
20080725, 20080726, 20080727, 20080728, 20080729,
};
vector<int>vec;
vec.resize( sizeof(date) );
remove_copy_if(date, date+20, vec.begin(), IsNotFriday() );
vec.erase( remove( vec.begin(), vec.end(), 0 ), vec.end() );
cout << vec.size();
}
>>使い方がヘンなだけ。
とご指摘くださった、この方法なのですが
デバッグしてみても、初回の条件判定からから、for文を抜けてしまって
forディレクティブが一度も実行されないのですが?
// 正しい使い方
TransFormFriday tff;
for_each( vec.begin(), vec.end(), tff );
for ( vector<int>::iterator it = tff.GetFriDay().begin(); //ここの部分
it != tff.GetFriDay().end(); ++it ) {
cout << *it << endl;
}
Banさんのご指摘なのですが
>>上では、TransFormFriday型の名前のない一時変数を引数に渡していることは大丈夫で
>>>すか。
for_each( vec.begin(), vec.end(), TransFormFriday() );
確かに、ここは悩んだところで第三引数に、TransFormFriday()と書くと
コンストラクタを呼んでいるようにも見えると、思った次第ですが
実際にコンテナに値は代入が行われているので半信半疑でした。
>>そして、見ての通り、tffは生成後、一度もoperator()を呼ばれていないです。
生成前のoperator()は呼ばれて、生成後は呼ばれていないと、そのせいで、
代入は行われるが(生成前)、取り出せない(生成後)原因なのでしょうか
>>tff(); TransFormFriday()();
そして、この部分なのですが
tff()はコンストラクタでしょうか、またTransFormFriday()()は
どの様な作用を持つのでしょうか。これらは、何処の部分に実装したらいいのでしょう
か?
>>Fの大文字にちょっと違和感が。
寝ぼけていましたww
以上です、宜しくお願いいたします。
> vector<int>vec;
> vec.resize( sizeof(date) );
> remove_copy_if(date, date+20, vec.begin(), IsNotFriday() );
> vec.erase( remove( vec.begin(), vec.end(), 0 ), vec.end() );
vector<int>vec;
vec.resize( sizeof(date) );
vector<int>::iterator last = remove_copy_if(date, date+20, vec.begin(),
IsNotFriday() );
vec.erase( last, vec.end());
...なんだけど、入力の要素数がすっごくデカいと無駄だし、
入力をファイルから読み込む場合とかだとそもそも初期サイズを決定できない。
なので:
#include <iterator>
...
vector<int> vec;
remove_copy_if(date, date+20, back_inserter(vec), IsNotFriday() );
>>>使い方がヘンなだけ。
> とご指摘くださった、この方法なのですが
> デバッグしてみても、初回の条件判定からから、for文を抜けてしまって
> forディレクティブが一度も実行されないのですが?
再現できません。前述のコードはコンパイル/実行を確認しました。
>>>上では、TransFormFriday型の名前のない一時変数を引数に渡していることは大丈夫
で
>>>>すか。
> for_each( vec.begin(), vec.end(), TransFormFriday() );
> 確かに、ここは悩んだところで第三引数に、TransFormFriday()と書くと
> コンストラクタを呼んでいるようにも見えると、思った次第ですが
> 実際にコンテナに値は代入が行われているので半信半疑でした。
TransFormFriday のインスタンスが作られて for_each に渡され、
for_eachから抜けた後捨てられます
>>>そして、見ての通り、tffは生成後、一度もoperator()を呼ばれていないです。
> 生成前のoperator()は呼ばれて、生成後は呼ばれていないと、そのせいで、
> 代入は行われるが(生成前)、取り出せない(生成後)原因なのでしょうか
...オブジェクトとかインスタンスとか、アナタ理解できていない。
> tff()はコンストラクタでしょうか、
いいえ。tffに対してTransFormFriday::operator()を呼び出してます。
この例ではシグニチャがvoid TransFormFriday::operator()( const int& ymd )なので、
実際にはymdに相当する引数が必要で、
int ymd = 20080101;
tff(ymd);
みたいな形になるわけですが、operator()ってのはこうやって呼び出すものです。
# operator()ってわかりにくいかな、と思って書いた単なる補足/蛇足です。
> またTransFormFriday()()はどの様な作用を持つのでしょうか。
名のない一時変数に対してoperator()を呼び出しても、この例で言えばあまり
意味はありません。ソイレントグリーンさんの最初のコードのようなものです。
> これらは、何処の部分に実装したらいいのでしょうか?
これらは単なる補足/蛇足なので、ここでは特別実装することはないはずです。
> for_each( vec.begin(), vec.end(), TransFormFriday() );
> 確かに、ここは悩んだところで第三引数に、TransFormFriday()と書くと
> コンストラクタを呼んでいるようにも見えると、思った次第ですが
> 実際にコンテナに値は代入が行われているので半信半疑でした。
それは、単にコンストラクタだけを呼んでいるのではなく、
「無名の一時変数を作って引数に渡す」という意味ですから、
デバッガでトレースなどすれば、その無名の一時変数には、
値が代入されるかと思います。
ただし、当然のことながら単なる一時変数ですので、その結果は残りません。
そして、その後に、まったく無関係のインスタンスtffが作成されますが、
これについては、コンストラクタだけが呼ばれたまっさらな別インスタンスに
過ぎず、一度もoperator()を呼ばれたことがありませんので、
当然コンテナには何も入っているはずがありません。
それはそれとして、
> 再現できません。前述のコードはコンパイル/実行を確認しました。
for_eachでコピーが走るので、うちでもソイレントグリーンと同じ結果が再現します。
見落としてました、正しい使い方はこうです。
tff = for_each( vec.begin(), vec.end(), tff );
επιστημη さんBanさんお世話になります
>>...なんだけど、入力の要素数がすっごくデカいと無駄だし
なるほど、back_inserter(vec)これだと確かに、無駄ができませんね
>>再現できません。前述のコードはコンパイル/実行を確認しました。
そうですか、当方では先の、επιστημη さんが示してくださったコードを
コンパイル実行しますと
20080704
20080711
20080725
としか表示できません
本来は
20080704
20080711
20080725
20080704
20080711
20080725
この様な結果を期待していたのですが、当方の設定がおかしいのかな?
>>...オブジェクトとかインスタンスとか、アナタ理解できていない。
そうですね、理解できてませんね、┐(´д`)┌ヤレヤレ さっぱりだな
Banさん
>>これらは単なる補足/蛇足なので、ここでは特別実装することはないはずです。
なるほど、そういうことでしたか、ありがとうございます
でもって、今も格闘中なのですが
単純に考えるために、int型の変数xと、出し入れするset/get関数を作って検証しました
ら、期待通り動きました
次にvectorコンテナは、デフォルトコンストラクタで初期化されのは判っていますが、
あえて初期化子でコンストラクタを呼び出してみました、これも期待通の
インスタンスがセットされました
そしてすると、元に戻り、問題の部分をデッバッガーで追ったところ
void operator()( const int& ymd )
{
~処理
}
この間は
vFriday [13](0,0,0,0,0,0,0,0,0,0,20080704,20080711,20080725)
となりますが
void operator()( const int& ymd )のスコープを抜けると
vFriday [10](0,0,0,0,0,0,0,0,0,0)
となり、コンストラクタで初期化されたままです?
vFridayをグローバル変数で宣言しますと
vFriday [13](0,0,0,0,0,0,0,0,0,0,20080704,20080711,20080725)
この結果は得られるのですが、それではコンテナを隠蔽できませんし、なぜこうなるのか
理解できません、for_eachディレクティブが生成している、vFridayの値はコピーコンス
トラクタなので(想像ですが)、インスタンスが生成されていないのでしょうか?
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class TransformFriday
{
vector<int> vFriday;
int y, m, d, x;
public:
TransformFriday() : y(0), m(0), d(0), vFriday(10), x(100){}
void operator()( const int& ymd )
{
y = ymd / 10000;
m = ymd % 10000 / 100;
d = ymd % 100;
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
if( ( ( y + y/4 - y/100 + y/400 + t[ m - 1 ] + d) % 7 ) == 5 )
vFriday.push_back( ymd );
}
vector<int>& GetFriDay(){ return vFriday; };
void AddX(){ x += 100;};
int GetX(){return x;};
};
int main()
{
vector<int>vec;
vec.push_back(20080701);
vec.push_back(20080704);
vec.push_back(20080705);
vec.push_back(20080706);
vec.push_back(20080707);
vec.push_back(20080708);
vec.push_back(20080711);
vec.push_back(20080712);
vec.push_back(20080713);
vec.push_back(20080714);
vec.push_back(20080715);
vec.push_back(20080719);
vec.push_back(20080720);
vec.push_back(20080721);
vec.push_back(20080722);
vec.push_back(20080725);
vec.push_back(20080726);
vec.push_back(20080727);
vec.push_back(20080728);
vec.push_back(20080729);
TransformFriday tff;
tff.AddX();
cout << tff.GetX() << endl;
for_each( vec.begin(), vec.end(), tff );
cout << *tff.GetFriDay().begin() << endl;
for ( vector<int>::iterator it = tff.GetFriDay().begin();
it != tff.GetFriDay().end(); ++it ) {
cout << *it << endl;
}
}
挙動についてはoperator()の中と、for_eachの前後でthisの
アドレスでも吐いてもらうとわかるのでは。
先に示したように、*基本的に値渡し* なので
* for_eachの戻り値* をとらないと結果はとれません。
# この意味では、メンバに参照を取らないこのファンクタでは
# 事前にtffを引き数にする意味が薄いですね…。
ほぼずばりのサンプルが載っていると思いますが
MSDNってみてますか?
挙動についてはoperator()の中と、for_eachの前後でthisの
アドレスでも吐いてもらうとわかるのでは。
先に示したように、*基本的に値渡し* なので
* for_eachの戻り値* をとらないと結果はとれません。
# この意味では、メンバに参照を取らないこのファンクタでは
# 事前にtffを引き数にする意味が薄いですね…。
ほぼずばりのサンプルが載っていると思いますが
MSDNってみてますか?
# モバイルから書いたら誤操作でだぶった…Orz
Banさんお世話になります、そして大変わかり易い解説いつもありがとうございます。
5つ前のBanさんの書き込み、何気にスルーしてました、ごめんなさい
>>それは、単にコンストラクタだけを呼んでいるのではなく、
>>「無名の一時変数を作って引数に渡す」
>>そして、その後に、まったく無関係のインスタンスtffが作成されますが、
>>これについては、コンストラクタだけが呼ばれたまっさらな別インスタンスに
>>過ぎず、一度もoperator()を呼ばれたことがありませんので、
>>当然コンテナには何も入っているはずがありません。
なるほど、そういうしくみだったんですね、まんまとひっかっかりました
お~じょうこきまんなぁ~
>>挙動についてはoperator()の中と、for_eachの前後でthisの
>>アドレスでも吐いてもらうとわかるのでは。
確認できました、確かにその通りでした
>>ほぼずばりのサンプルが載っていると思いますが
>>MSDNってみてますか?
イテレータをまわして、インスタンスは+=で取得するパターンのものですね、見てません
でした、やっぱり見ないとダメですね....orz
tff = for_each( vec.begin(), vec.end(), tff );
for_eachディレクティブに、TransformFridayを食わせて、TransformFridayを得るわけで
すね、自己代入してるんだ、おもしろいですね、
=演算子でオブジェクト間の、代入ができるからこそ、成り立つわけですね、そしてこう
することで初めてoperator()が動く訳か・・・
納得しました。
επιστημηさん、Banさんありがとうございました、すっきりしました。
解決とさせていただきます。