1 名前:デフォルトの名無しさん [2009/01/11(日) 11:13:44 ] C++標準ライブラリの一つ、STLについて。 前スレ 【C++】STL(Standard Template Library)相談室 10 pc11.2ch.net/test/read.cgi/tech/1219719677/ 過去ログ・リンク・書籍紹介は >>2 以降
130 名前:デフォルトの名無しさん [2009/02/23(月) 18:07:27 ] 関数オブジェクトの使い方として、以下のような記述は許されますか? // generate アルゴリズムを使ってコンテナに公差1の等差数列を代入する template < class T > class Gens { public: Gens() : s_( 0 ) {} Gens( T i ) : s_( i ) {} T operator () (){ return s_++; } private: T s_; }; int main() { vector< int > vector1( 20 ); Gens< int > gens( 10 ); // 問題はココと generate( vector1.begin(), vector1.end(), gens ); // ココ } 普通は generate( vector1.begin(), vector1.end(), Gens< int >() ); のように書きますが、 あらかじめオブジェクトを構築しておいて、 そのオブジェクトを引数として渡すというものです。 上記の例ではあらかじめオブジェクトを構築することで ジェネレータが作り出す数列の初項を10に設定しています。
131 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 20:10:05 ] >>130 全く問題ないよ
132 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 21:15:07 ] >>130 >上記の例ではあらかじめオブジェクトを構築することで >ジェネレータが作り出す数列の初項を10に設定しています。 なら generate( vector1.begin(), vector1.end(), Gens< int >( 10 ) ); でもインジャネーノ?
133 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 21:28:02 ] >>130 そもそも内部状態を持つ関数オブジェクトをアルゴリズムで使うのはよろしくない www.kijineko.co.jp/tech/superstitions/functor-is-not-copied-in-algorithm.html
134 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 21:49:05 ] コピー禁止すりゃいいんじゃね?
135 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 22:29:12 ] 誰にも突っ込んでもらえなかったけど、コピー禁止してどうやって渡すんだ orz
136 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 22:33:29 ] >>133 たしかに規格上は保証がないかもしれないが、なんだか屁理屈に聞こえる。
137 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 23:43:39 ] >>136 同感だな 内部状態を持つ関数オブジェクトって普通にありえるからな なんか現実を無視して重箱のすみを突いているって感じだな
138 名前:デフォルトの名無しさん mailto:sage [2009/02/23(月) 23:53:59 ] いや、これははまるぞ 移植してバグったとき、大変そうだ
139 名前:デフォルトの名無しさん [2009/02/24(火) 00:01:50 ] ん? マッサーの STL 本では generate のサンプルで内部状態を保持しているし メイヤーズの Effective STL でも、関数オブジェクトの利点は 「必要に応じていくつでも状態を格納できること」と書いてるぞ?(たとえば p.161 ) 述語は純粋関数でないとだめだけど。 サッターの C++ Coding Standardsでは 「述語は関数オブジェクトの部分集合である」( p.172 )としていて すなわち述語でない関数オブジェクトは純粋関数でなくても良いということになってるぞ? どっちなんだ。
140 名前:デフォルトの名無しさん [2009/02/24(火) 00:05:52 ] ちなみに、generate の第三パラメータは述語ではないので、 (マッサー、メイヤーズ、サッターの本にあるとおり) 純粋関数でなくても良いということになる。
141 名前:デフォルトの名無しさん [2009/02/24(火) 00:12:15 ] 今、シルトの本も調べてみたが、やっぱり関数オブジェクトの利点として 「値を格納したり、追加機能を実装できる」( p.230 )と書いてるな。
142 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 00:12:48 ] すまん、全部 age ちまった・・・ orz
143 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 00:44:58 ] vectorの連続性と一緒だな 普通はコピーなんてしないし、規格作った方もそんなつもりじゃなかったけど ちゃんと書いてないせいで信用できないし、コピーしちゃう実装を誰かが作っても責められない そんな誰も得しない状態 0xで直るんかね
144 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 00:52:16 ] vectorの格納領域は「必ず」連続するようになったのは1998年以降だから まぁ、いまどきのコンパイラならもう必ず連続すると考えていいんじゃないの。
145 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 11:38:30 ] std::vector<int> v; v.reserve(10); ... // v に値を格納 std::copy(v.begin(),v.end(),std::ostream_itreator<int>(std::cout,",")); このコードの copy 内の ostream_iterator... の部分て何を行っているのですか? コンテナの要素をループで書き出してるのは分かるのですが、内部でどのような処理をしているのでしょう?
146 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 12:43:55 ] >>138 俺もはまった boost::refして誤魔化した
147 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 12:53:46 ] ええ、どこのベンダだよ
148 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 16:00:32 ] vectorの格納領域と同じで、標準化委員会がどっかで修正コメントだしてないのかな?
149 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 16:14:34 ] >>130 俺なら output_iterator を受け取る関数を作って back_inserter を渡す。 std::vector なら reserve してからね。 >>133 良くないのはそうだけど、総和とかには使うし、命名とかコーディングスタイルの話になるんじゃないか?
150 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 18:48:24 ] >>146 それどこのSTLライブラリ? で、どんなコードではまった?
151 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 20:48:17 ] >>149 ライブラリの内部実装の話を命名やコーディングスタイルでどうするの?
152 名前:デフォルトの名無しさん mailto:sage [2009/02/24(火) 23:49:33 ] >>145 ttp://msdn.microsoft.com/ja-jp/library/0c6y7x31(VS.80).aspx
153 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 00:08:40 ] >149 総和系なら accumulate があるべ。
154 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 08:55:19 ] 状態を持つと並行処理できないじゃないか。 なーんてね
155 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 09:03:23 ] >>151 内部状態を持つ関数オブジェクトを使う話で、内部実装の話はしてないよ。 使わないほうがいいけど、使うなら注意を喚起するとか、専用の関数を作って封じ込めるとか、という話。 >>153 全くその通りでした。
156 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 19:52:40 ] mapは構造体をキーに持つことができないのでしょうか? 具体的には、mapを使って2枚の画像の対応点を記録しようとしています。 typedef struct point { int x; int y; }point; map<point, point> correspond; point p1, p2; /*p1とp2の座標を入力*/ correspond.insert( pair<point, point>(p1, p2) ); としてコンパイルするとerror C2784が出ます。 環境はVS2008、XP SP3を使っています。 どうしたら解決できるでしょうか?
157 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 20:04:06 ] エラーの内容から二つのpointを比較できないコードであるということがわかるので、mapの為に比較関数を用意する。 方針としては、グローバルにpointの大小を判別するbool operator<(const point&, const point&)を定義するか、 correspondの宣言の歳にmap<point, point, compare_t> correspond(compare);とする (ただしcompare_tは戻り値boolで引数に(const point&, const point&)を取ることができる関数オブジェクトまたは関数の型で compareはそのインスタンス)
158 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 20:25:45 ] >>157 素早い回答ありがとうございます。 pointのxとyどちらでソートすべきか比較関数を用意してやればよいということでしょうか?
159 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 20:32:21 ] うん、例としては bool f(const point& lhs, const point& rhs){ return lhs.x < rhs.x && lhs.y < rhs.y; } のようなものを定義して map<point, point, bool(*)(const point&, const point&)> correspond(f); かな? operator<を使う方法についてはeffective C++とか参考にすれば、 綺麗に実装する方法が載ってると思う
160 名前:デフォルトの名無しさん mailto:sage [2009/02/25(水) 20:39:54 ] >>159 具体例までありがとうございます。 map 比較関数 でググったらいくつか例も出てきたので出来そうです。 よく考えるとmapは2分木を利用してるんだから自前の比較関数を用意してやる必要があるのは当たり前ですね。 勉強になりました。
161 名前:デフォルトの名無しさん mailto:sage [2009/02/27(金) 20:33:14 ] C++やSTLではコンテナの全要素を出力するときどのようにするのでしょうか? kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/img/8944.txt 今は上のようにやってます。 list vector mapやDataのようなクラスが増えていくにつれコードが増え、似たような処理が何回も出てきそうです
162 名前:デフォルトの名無しさん mailto:sage [2009/02/27(金) 20:37:20 ] std::list<T>をTにすればコンテナ全種に使えるようになるはず。
163 名前:デフォルトの名無しさん mailto:sage [2009/02/27(金) 20:41:47 ] よくわからないけどこういうこと? template<typename T> std::ostream &print(std::ostream &ost, const T &cont) { ost << "["; std::copy(cont.begin(), cont.end(), std::ostreambuf_iterator<T::value_type>(ost, ",")); ost << "]"; return ost; }
164 名前:デフォルトの名無しさん mailto:sage [2009/02/27(金) 20:50:54 ] コンテナを取るんじゃなくて、algorithmみたいに範囲を取るようにすれ。 template<typename Iterator> std::string to_str2(Iterator first, Iterator last) { std::ostringstream oss; Iterator it = first; oss << "["; if (it != last) { while (true) { oss << (*it); ++it; if (it == last) break; oss << ", "; } } oss << "]"; return oss.str(); }
165 名前:デフォルトの名無しさん mailto:sage [2009/02/27(金) 20:51:31 ] まぁそれだけだとlist<list<...>>みたいなのに適応できないけどな
166 名前:161 mailto:sage [2009/02/27(金) 23:02:22 ] >>162 ほんとですね、全部なおしました std::ostream& operator<<(std::ostream & rhs, const <T>& lhs)はダメなんですね 当たり前なんでしょうけど >>163 こういう書き方もできるのですね、、、 p to_str(dlist)かp 'to_str(std::list<Data, std::allocator<Data> > const&)' (dlist)でgdbから呼べるのですが、 ostreamかtemplate使うと消える?みたいなのでObject.to_string()とテンプレートではないto_str(x)は用意するので ostreamやostringstreamを極力使わずにできればなと >>164 ,165 Iteratorの中身がコンテナじゃなさそうな場所に使ってみます
167 名前:デフォルトの名無しさん mailto:sage [2009/02/28(土) 00:04:03 ] とりあえず、rhsは right hand side(右側)の略なんだから lhs << rhs って形にしようぜw
168 名前:デフォルトの名無しさん mailto:sage [2009/03/02(月) 12:55:03 ] 関数オブジェクトにしといてfor_each()じゃだめなのか
169 名前:デフォルトの名無しさん mailto:sage [2009/03/03(火) 21:45:22 ] >>168 それ、コードではどうやるの
170 名前:デフォルトの名無しさん mailto:sage [2009/03/04(水) 01:25:00 ] こんな感じ? template <class T> struct Out { void operator()(T& i) const { std::cout << i << ' '; } }; int main() { int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; std::list<int> aa(a, a + sizeof(a) / sizeof(a[0])); std::for_each(aa.begin(), aa.end(), Out<int>()); }
171 名前:デフォルトの名無しさん mailto:sage [2009/03/04(水) 12:40:27 ] ostream_iteratorにassignという手も
172 名前:デフォルトの名無しさん mailto:sage [2009/03/04(水) 16:04:02 ] 例としてよく引き合いに出されるのは ostream_iterator に copy だと思うが・・・
173 名前:デフォルトの名無しさん mailto:sage [2009/03/04(水) 16:19:22 ] for_eachを使うと copy よりも凝った出力形式を作れるってくらいかな
174 名前:デフォルトの名無しさん mailto:sage [2009/03/05(木) 09:49:02 ] #include <pstade/oven/io.hpp> #include <pstade/oven/make_range.hpp> int main() { namespace oven = pstade::oven; std::list<int> l = a|oven::copied; std::cout << (oven::make_range(l)) << "\n"; }
175 名前:デフォルトの名無しさん mailto:sage [2009/03/10(火) 23:08:36 ] >>136 ,143 www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#92 今のドラフトでは以下の記述が追加されている。 > algorithms that take function objects as arguments are permitted to copy those function objects freely アルゴリズム内でどうコピーされるかは基本的に実装任せってことになるらしい。 for_each() の戻り値はまったく使えないことになりそうだ。
176 名前:デフォルトの名無しさん mailto:sage [2009/03/14(土) 16:56:46 ] >>175 for_eachの戻りはコピーされた関数オブジェクトに内部状態が反映されてるんじゃなかった?
177 名前:デフォルトの名無しさん mailto:sage [2009/03/14(土) 18:17:17 ] >176 関数オブジェクトに全要素を通して処理した結果の状態が保持されていることを期待するだろうが、 極端に言えば各要素の呼び出し毎に新しくコピーした関数オブジェクトを渡されたりすると、期待する 結果と異なる。 参照使うなりコピーされても大丈夫なようにはできるからまったく使えないは言い過ぎ。 とはいえ、そういう用途なら accumulate 使えばいいじゃん、とは思う。
178 名前:デフォルトの名無しさん mailto:sage [2009/03/14(土) 18:22:46 ] boost::ref使って渡せばいいんじゃないか。boost::mpl::for_eachではうまくいった
179 名前:デフォルトの名無しさん mailto:sage [2009/03/18(水) 22:23:42 ]