1 名前:デフォルトの名無しさん mailto:sage [04/11/25 21:11:32] C++ のジェネリックプログラミングの話をしましょう。 以下のスレッドを統合するスレです。 STLスレッド Part1 pc.2ch.net/tech/kako/1004/10042/1004287394.html Part2 pc3.2ch.net/tech/kako/1026/10267/1026793823.html 【C++】Boost使い集まれ! pc3.2ch.net/test/read.cgi/tech/1033830935/ (html化待ち?) Generic Programming with C++ Template pc.2ch.net/tech/kako/1008/10085/1008593126.html 【C++】template 統合スレ -- STL/Boost/Loki, etc. pc2.2ch.net/tech/kako/1037/10377/1037795348.html 【C++】template 統合スレ -- Part2 pc2.2ch.net/test/read.cgi/tech/1047978546/ (html化待ち) 【C++】template 統合スレ -- Part3 pc5.2ch.net/test/read.cgi/tech/1066493064/ (html化待ち) 【C++】template 統合スレ -- Part4 pc5.2ch.net/test/read.cgi/tech/1083550483/ (html化待ち) 【C++】template 統合スレ -- Part5 pc5.2ch.net/test/read.cgi/tech/1091522597/ 関連スレ、その他リンクは >>2-5 あたりに。
651 名前:デフォルトの名無しさん mailto:sage [2005/06/07(火) 22:12:38 ] 省略されてるだけ。 template <class /*T*/> class foo;
652 名前:デフォルトの名無しさん mailto:sage [2005/06/07(火) 22:27:41 ] >>651 サンクスです。とすると何らかの型を受け取るけど、 その型の情報は無視するよ、っていうことなんですね。 これをもとにもう一回読んでみます。
653 名前:デフォルトの名無しさん mailto:sage [2005/06/07(火) 22:32:56 ] >>650 int f(int i); int g(int); // これも脳内エラーが出るか?
654 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 00:28:08 ] >>650 例えば、 template< template<class T, class A> class Vector> struct hoge { typedef T value_t; }; typedef hoge<std::vector> hv_t; としても、この時点では”T"はまだ決まってないわけだから 名前付けても使えないのです。 無論、”Vector"もこのままでは使えません。 実際の使用には template< tempalte<class,class> class V> struct hoge { template<class T,class A> struct bind { typedef V<T,A> type; }; }; typedef hoge<std::vector> hv; typedef typename hv::template bind<int,std::allo..>::type のように使うことになりますね。
655 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 00:31:15 ] 補足ですが、 使えない == typedefできないということです。
656 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 00:41:11 ] >>654-655 とても650の理解を助けるとは思えない。
657 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 01:10:19 ] 間違ったことは言ってないが、質問の答えとしては完全にズレてるな。
658 名前:654 mailto:sage [2005/06/08(水) 01:22:29 ] >>656-657 この場合 >"template テンプレート パラメータ"の意味が理解できないッス。 と書いてあるところから、名前云々は関係ないと思うのですが・・
659 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 10:35:01 ] >>658 会話になってないな。もういいから喋るな。
660 名前:デフォルトの名無しさん mailto:sage [2005/06/08(水) 21:38:27 ] >>650 です。 皆さんありがとうございます。 >>654 さんのご意見もとても理解の助けになりました。
661 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:01:15 ] typedf templateってどうなったの?
662 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:13:16 ] template< template<class T, class A> class Vector> struct hoge { typedef T value_t; }; template<class B> typedef hoge<std::vector<B> > hv_t; typeof(hv_t<int>::value_t) i; みたいにtypedefの一文をテンプレート化できるんだっけ。
663 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:32:30 ] >>662 それはだめだろ。 template-templateパラメタのtemplateパラメタ(この場合T) に言及するのは意味的におかしい。
664 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:43:39 ] こうじゃないか? template <typename> struct hoge; template <template <typename, typename> class V, typename T, typename A> struct hoge<V<T, A> > { typedef T value_t; }; template <typename T> typedef hoge<std::vector<T> > hv_t; hv_t<int>::value_t i;
665 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:49:01 ] typedef templateを導入するなら変数templateや名前空間templateも欲しい。 と無責任に言ってみるテスト。
666 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 08:56:13 ] >>664 あーなるほど。C++よく分らないから適当に書いてみたんだけどそれなら理解できるw >template <template <typename, typename> class V, typename T, typename A> > struct hoge<V<T, A> > こうやって部分的特殊化で各パラメータ間の関係を表現できるのね。 >>663 >template <typename T> typedef hoge<std::vector<T> > hv_t; 問題はこの部分で、パラメータvector<T>の高階性(?!)を維持してくれるのかどうかってところかねえ。 >>665 変数templateとはどんなもんでしょ?
667 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 11:34:08 ] もしも変数テンプレートがあったとしたらこんな感じ? template <typename T> const T *NULL = 0; int *pi = NULL; char *pc = NULL; #include <cstdio> int main() { std::printf("%p", NULL<void *>); }
668 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 11:59:30 ] >>667 >int *pi = NULL; >char *pc = NULL; これを許すとまた規則が複雑になるな。
669 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 12:14:33 ] class null { public: template<typename T> operator T*() const { return 0; } }; const null NULL; int *ip = NULL; char *cp = NULL; printf("%p", (void*)NULL); でいいような気がす
670 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 12:16:52 ] 誰もそんな話ししてないわけだが
671 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 13:24:53 ] >>667 引数とるコンストラクターはどうなるんだ。
672 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 13:52:48 ] typedef template ムチャ欲しいな。
673 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 14:26:04 ] >>667 今のC++の型の取り扱いにあわせると template<typename T> const T *NULL = 0; は,右辺がリテラルの0でこれは型がintだからポインタ型に変換できず, Tをどの型でinstantiationすれば良いのか判断できずコンパイルエラーになる, っていう扱いが妥当だと思いますよ. もうちょい厳密に変数テンプレートを定義しようとすると, 結局,型推論のためのautoキーワードの拡張 auto a = b; // typename(b) a = b; の構文糖 と同じになると思います.Andrew Koenigあたりがこのautoキーワードの代わりに >>667 の構文を提案してたはず.
674 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 14:35:13 ] >>673 >>667 の代わりに、 template <typename T> struct wrap{static const T *null;}; template <typename T> const T *wrap<T>::null = 0; と書けることを考えると、今の扱いなら、 ・template <typename T> const T *NULL = 0; の時点では何も起こらない。 ・printf("%p" NULL<void *>); の点でインスタンス化が引き起こされ、void *const *を0で初期設定しようとし、成功。 が妥当じゃないのか?
675 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 14:50:45 ] >>670 そうでなくて、必要性が全く感じられないと言っている まともな利用例ぐらい出さないと
676 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 14:56:07 ] >>674 その使い方だと常に明示的にインスタンス化しないといけない (NULLを利用するたびに型パラメータを与えないといけない)わけですよね? それは利用範囲が著しく限られませんか?
677 名前:667 mailto:sage [2005/06/09(木) 15:03:10 ] ところで俺は変数テンプレートは全く要らないと思うんだけどな。 俺も669と同じようなのを考えたことはあるけど。
678 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 15:10:28 ] >>676 使い道がないのは同意。 ただ、仮に現在のテンプレートの延長で「変数テンプレート」なるものを定義するなら、 >>674 で言ったようになるはずだと思った。 >>673 のような機能を導入するなら別の名前・構文を考えるべきだと思う。
679 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 15:26:38 ] 型推論はされるとして、 NULLみたいに初期化子に使うとちょっと面白そうな… クラス階層のあるところでPTHREAD_MUTEX_INITIALIZERみたいなやつ。
680 名前:デフォルトの名無しさん mailto:sage [2005/06/09(木) 15:29:21 ] >>678 確かに「変数テンプレート」という名前は非常にまずいですね. ただ構文については既存のキーワード使うとするとこれぐらいしかないような気がします.
681 名前:デフォルトの名無しさん mailto:sage [2005/06/12(日) 15:01:48 ] アドビのオープンソースってど?流行ると思う? STL、boostを基に、ウィンドウをスクリプトから生成する画期的システム 仮想マシンを実現とか、内容は理解を超えていた (つД`) いわゆるチョット修正のときに威力を発揮すると思う SEはどんな些細なこともPGに要望しなけりゃならない PGは思いつきの修正のために仕事が増えるばかり だれか人柱になってください、やっぱアドビ待ちなのかな
682 名前:デフォルトの名無しさん mailto:sage [2005/06/12(日) 17:16:13 ] >>681 AdamとEve( ttp://opensource.adobe.com/ )のことか?なかなか 普及は難しいんじゃないかなぁ…
683 名前:デフォルトの名無しさん mailto:sage [2005/06/13(月) 00:40:41 ] 質問です。 BCC 5.5上のテンプレートのバグはどのようなものが あるのでしょうか。 ・・・特に大きいタイプリストを渡すと、他の特殊化に指定 したクラスが別のクラスに化けるとか、そんなのないですか?
684 名前:デフォルトの名無しさん mailto:sage [2005/06/13(月) 10:45:49 ] >>683 質問するときはやりたいこと、実際にやったことを書いた方が良い。
685 名前:デフォルトの名無しさん mailto:sage [2005/06/13(月) 14:20:43 ] >>683 どういうバグかは知らんがboostが満足に使えない。
686 名前:683 mailto:sage [2005/06/13(月) 21:39:52 ] 自己解決しちゃいました。 経緯だけ説明しますと、Modern C++ Designのマルチメソッドを 自分の使いやすい形に改良して使っていたんです。で特殊化の 際タイプリストを template<..,class Head,class Tail>struct Dispatcher<...,Typelist<Head,Tail>,...>{ ...省略 }; と展開していて、6ほどの長さのタイプリストをわたしたところエラー吐かれました。 (5つまでは普通にコンパイル&動作しました) これを template<..,class TList>struct Dispatcher<...,TList,...>{ ...省略 }; としHeadにアクセスするときTList::Head,Tailにアクセスするときは TList::Tailとするようにしたら今度は何十の長さでもコンパイルできました。 前者のコンパイルの仕方にバグがあるんでしょうかね・・・
687 名前:デフォルトの名無しさん mailto:sage [2005/06/13(月) 23:51:10 ] BCCなんか使うなよ
688 名前:デフォルトの名無しさん mailto:sage [2005/06/14(火) 17:45:57 ] もしかして、クラステンプレートのメンバ仮想関数って勝手に実体化される?
689 名前:デフォルトの名無しさん mailto:sage [2005/06/14(火) 17:58:42 ] >>688 どんなコードでそう思った?
690 名前:688 mailto:sage [2005/06/14(火) 18:10:23 ] ものすごく単純化すると、 class base { public: virtual void foo() = 0; }; template <class> class derived : public base { public: virtual void foo() { std::cout << "呼ばれた\n"; } }; int main() { derived<int> d; static_cast<base&>(d).foo(); } こんな感じ。
691 名前:デフォルトの名無しさん mailto:sage [2005/06/14(火) 18:24:16 ] >>690 それってderived<int>型の変数dを宣言したからderived<int>が実体化されているだけのように見えるが。
692 名前:688 mailto:sage [2005/06/14(火) 18:28:53 ] derived<int> が実体化されるのと derived<int>::foo が実体化されるのは別じゃないですか? クラステンプレートのメンバって呼ばれるまで実体化されませんよね?
693 名前:デフォルトの名無しさん mailto:sage [2005/06/14(火) 18:31:57 ] >>688 規格では詳しくは規定されていないっぽい。 実際は ・derived<int>のインスタンスが宣言された ・derived<int>*からbase*の変換が行われた のいずれかをトリガとして、仮想関数をすべて実体化することになると思う。
694 名前:688 mailto:sage [2005/06/14(火) 18:40:33 ] >>693 サンクス。未定義ってことですか。 一応、明示的に実体化しておいたほうがよさそうですね。
695 名前:デフォルトの名無しさん mailto:sage [2005/06/14(火) 18:47:45 ] >一応、明示的に実体化しておいたほうがよさそうですね。 なんでそうなる? ついでに、「未定義」と「未規定」は違う。
696 名前:688 mailto:sage [2005/06/14(火) 18:50:17 ] ん? 規定はされていなくても、正常に動くことは保証されているってことですか?
697 名前:693 mailto:sage [2005/06/14(火) 18:57:55 ] 言い方が不正確だったな。 規格には、「メンバ関数は、その定義が必要とされるとき実体化される(意訳)」とある。 で、virtual関数については、いつ「定義が必要とされる」か正確に規定している部分が(俺の見た限りでは)なかった。 従って、virtual関数の正確な実体化のタイミングは規定されていないことになる。 それでも、「必要」になり次第実体化されることは保障される。
698 名前:688 mailto:sage [2005/06/14(火) 19:22:06 ] あー、なるほど。 規定されていないのは実体化されるタイミングだということですね。 どうもありがとうございました。
699 名前:デフォルトの名無しさん mailto:sage [2005/06/26(日) 18:25:16 ] int k = 0; for (vector< set<int> >::iterator it = v.begin(); it != v.end(); ++it) it->insert(k++); を boost::lambda か何かを使って for_each でシンプルに書けませんか? メンバー関数に bind する仕方がよく分からないんですが・・・
700 名前:デフォルトの名無しさん mailto:sage [2005/06/26(日) 19:33:36 ] >>699 typedef std::set< int > set_type; typedef std::vector< set_type > vector_type; void f( vector_type& v ) { using namespace boost::lambda; int k = 0; std::for_each(v.begin(), v.end(), (protect(bind((std::pair<set_type::iterator,bool> (set_type::*)(int const&))(&set_type::insert), _1, var(k)++)))(*_1)); } ○ boost::lambda か何かを使って ○ for_each で × シンプルに
701 名前:700 mailto:sage [2005/06/26(日) 19:49:39 ] メンバ関数に限らず、オーバーロードが絡むと lambda は使いにくいな。
702 名前:デフォルトの名無しさん mailto:sage [2005/06/27(月) 06:52:07 ] protect要るか? >>701 C++は名前が重なった場合の簡潔な指名定方法がないしね。 lambdaに限らず面倒。 typeofがBoostに入るそうだから、そのうち頑張って改善されるといいな。
703 名前:700 mailto:sage [2005/06/27(月) 07:50:29 ] >>702 こんな感じで変形していったが、途中のやつの エラーメッセージがひどくて(数100行ぐらい出る)、 何がまずかったのかよくわかってない。 × ((*_1)->*insert)(var(k)++) × bind(insert, *_1, var(k)++) ○ (protect(bind(insert, _1, var(k)++)))(*_1)
704 名前:702 mailto:sage [2005/06/27(月) 22:11:02 ] >>703 その3つの最初から間違ってるよ。 for_eachなんだから_1にはイテレータではなく参照が入る。よって _1をdereferenceする必要はない。 まあ同じなんだけど、俺ならオーバーロードが絡む場合は メンバ関数の特定を追い出すかな。 void hoge(vector<set<int> >& v) { typedef set<int> set_type; pair<set_type::iterator,bool>(set_type::*insert)(const int&) = &set_type::insert; int k = 0; for_each(v.begin(), v.end(), bind(insert, _1, var(k)++)); }
705 名前:700 mailto:sage [2005/06/28(火) 00:20:42 ] >>704 うわ、とんでもない勘違いをしていたよ。 ありがとう。
706 名前:デフォルトの名無しさん mailto:sage [2005/07/05(火) 14:15:55 ] ttp://d.hatena.ne.jp/soleil/searchdiary?word=%2a%5b%c5%fd%b7%d7%5d ここに書いてあった struct Mean ってどう使うの? 例がないと分からない functorなのは分かったけど
707 名前:デフォルトの名無しさん mailto:sage [2005/07/05(火) 14:27:54 ] int array[] = {1, 3, 5}; std::vector<double> v = ...; int ma = Mean<int *>()(array, array + 3); double mv = Mean<std::vector<double>::iterator>()(v.begin(), v.end()); こんな感じじゃないか?
708 名前:デフォルトの名無しさん mailto:sage [2005/07/05(火) 16:19:10 ] for_eachにかけるものではないのね でも便利そう thx
709 名前:デフォルトの名無しさん mailto:sage [2005/07/05(火) 16:25:40 ] >>707 のとおりにやってみたけど コンパイル通らなかったよ
710 名前:デフォルトの名無しさん mailto:sage [2005/07/05(火) 17:04:14 ] >>706 > 算術平均を求める Mean を書き直すと以下のようになる > (もちろん Sum も反復子を使うように変更してあることが前提) ちゃんとSumもコード書いた? んで、漏れなら、合計値(累積値)を求めるアルゴリズムaccumulateを使い 平均値は: void f(vector<double>& m) { double avg = accumulate(m.begin(), m.end(), 0.0) / m.size(); } のようにして求めるな。分散・標準偏差、RMSあたりも似たような実装ができる。
711 名前:デフォルトの名無しさん mailto:sage [2005/07/06(水) 04:42:18 ] >>710 わざわざ関数にするのか? コードの大きさを抑えるのにはいいけど。
712 名前:デフォルトの名無しさん mailto:sage [2005/07/06(水) 07:22:20 ] >>711 しない。入力が何で出力が何か明確にしたかったので、関数形式で書いただけ。 実際に関数にするなら、template、inline、引数にはconst、戻値の型を明記、あたりが必要です。 蛇足で糞コード晒す。 template <typename T> struct square : public binary_function<T, T, T> { T operator()(const T& lhs, const T& rhs) { return lhs + rhs*rhs; }; }; double ms = accumulate(m.begin(), m.end(), 0.0, square<double>()) / m.size(); double rms = sqrt(ms); double stdev = sqrt(ms - avg*avg);
713 名前:デフォルトの名無しさん mailto:sage [2005/07/06(水) 08:07:25 ] STLは連続した、同じような事の繰り返し処理には滅法強いな。
714 名前:デフォルトの名無しさん mailto:sage [2005/07/06(水) 20:49:48 ] >>713 あなたの人生もSTLで簡単になりますよ。 void silly_life(life& your_life) { struct { static int daily(day& d) { d.nebou(); d.nichan(); d.onanu(); d.shigoto(); d.nichan(); d.onanu(); d.neru(); return 0; } }; std::for_each(your_life.begin(), your_life.end(), daily); } 久しぶりにtemplate見たよ。。。C#使いづれ〜。。。orz
715 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 00:00:05 ] それがSTLクオリティ。 語呂悪いな。
716 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 07:31:19 ] 速度が重要になるコードを書かなければなのですが、 やはりSTL経由の連続処理は、速度的に不利なんでしょうか? 一応自分なりに、次レスに書いたような実験をしてみたのですが、 プロファイル結果はSTL版hoge()が平均301msに対し、 シンプルなリストhage()の方が平均12msと、圧倒的な差に…。 今更自前リストなんて使うのは、考えただけで頭が痛くて。 なにかテストに落ちがないか、 或いはSTL版速度向上のための抜け道が無いか、教えて頂けないでしょうか。
717 名前:714 行制限のため、見づらくてすいません mailto:sage [2005/07/07(木) 07:35:09 ] #include <list> struct simple_list{ int val; simple_list* next; }; template <typename T> void hoge( T first, T last ){ int sum = 0; while( first != last ) sum += *(first++); }; void hage( simple_list* sl_first ){ int sum = 0; while( sl_first ){ sum += sl_first->val; sl_first = sl_first->next;} }; int main(){ std::list<int> listInt; for( unsigned long i=0; i < 100000; ++i ) listInt.push_back(i); simple_list* sl_first = new simple_list; simple_list* sl = sl_first; for( unsigned long c=0; c < 100000; ++c ){ sl->val = c; sl->next = new simple_list; sl = sl->next; } sl->next = NULL; hoge( listInt.begin(), listInt.end() ); hage( sl_first ); while( sl_first ){ sl = sl_first->next;delete sl_first; sl_first = sl; } return 0; }
718 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 07:51:04 ] >>716 プロファイルでは最適化は有効にしてる? 最適化しないと比較にならないし、最適化すると hoge(), hage() が sum を返してないので、最適化で処理自体が消えてダメかもしれない。 hoge の sum += *(first++); を { sum += *first; ++first } にすると、少し違うかもしれない。
719 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 07:51:41 ] >>716 最適化した? うちじゃ hoge(): 8.46567 ms hage(): 7.92051 ms くらいなんだけど 環境はg++ (3.3.5)
720 名前:716 mailto:sage [2005/07/07(木) 08:08:12 ] 我ながら非道い sl->next = NULL;を削って sl->next = new simple_list; を sl->next = (c != 100000-1) ? new simple_list : NULL; とでも >>718-719 最適化をすっかり忘れていました。 なぜだかsumを返すようにしてもhogeの方が消えてしまうのですが もう少し試行錯誤してみます。 いずれにせよ力づけられました。ホッとしています。 レスありがとうございました。
721 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 08:20:05 ] >>720 返すだけで戻り値を使ってないんじゃ、と消えるかもしれないな。 チェックもかねて、画面に値を出すようにすれば大丈夫じゃない? (そこまでやっても、ただの定数に置き換えてしまうコンパイラとかあるかもしれない。) 最終的にはアセンブリを吐かせて確認するといい。
722 名前:716 mailto:sage [2005/07/07(木) 08:25:49 ] 最適化無しで719さんの方法で15%ほど速く >>721 もしかしたらtemplateだったせいかも知れないです。インライン化されていたのかな。 templateを外したらhogeも出ました hoge: 5.579 ms hage: 5.313 ms (vc++6) 朝からお騒がせしました、お二人(三人?)に再度感謝です
723 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 08:31:10 ] その程度の処理だとlistは兎も角、vectorは普通の配列と全く同じ速度出るよ。 #つーか、gccでもVC++でもstlの有無で全く同じ(質の)コード吐くんだけどね。
724 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 18:13:33 ] >>723 VCだと vector>=配列 になるときもない?(誤差範囲内だけど) GCCは vector使うと少し遅くなる気がした。
725 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 18:23:22 ] その辺は具体的なコードを提示して比較でもしない限りなんとも言えないなぁ。 そもそも最適化で消えないコードでって条件になっちゃうし。
726 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 18:30:29 ] vectorのiteratorは大抵の処理系/STL実装で非デバッグ時には単なるポインタだろ。
727 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 18:34:16 ] >>722 ちなみに std::list が double-linked list だということは知ってるよな
728 名前:デフォルトの名無しさん mailto:sage [2005/07/07(木) 23:52:14 ] doubleじゃないSTLのlistを提示しない限りそのレスは無意味
729 名前:デフォルトの名無しさん mailto:sage [2005/07/08(金) 00:55:24 ] >>728 おれは>727じゃないけど、なんで?
730 名前:デフォルトの名無しさん mailto:sage [2005/07/08(金) 01:02:35 ] そういえばslistは標準じゃないんだな。 STLPortにはあるけど。
731 名前:デフォルトの名無しさん mailto:sage [2005/07/08(金) 20:43:04 ] 次のようなコードがあるとします: struct base1 { base1(int x) {}; }; struct base2 { base2(int x, int y) {}; }; // IF<P,T,F>クラステンプレートは、Pが非0のときT、0のときFをIF::typeにtypedefする template <int N> struct derived : public IF<N,base1,base2>::type {}; このとき引数の数が異なるコンストラクタを持つ基底クラスをテンプレートで切り替え、 派生クラスのコンストラクタから、基底クラスのコンストラクタを呼び出したいのです: derived<1> d(0); // base1から継承し、コンストラクタは引数1 derived<0> d(0, 1); // base2から継承し、コンストラクタは引数2 基底クラスのコンストラクタを呼び出すときには、派生クラスの初期化リストを使います。 ところが、派生クラスのコンストラクタ初期化リストでは、基底クラスのコンストラクタ 以外呼べませんから、次のように多重定義できません: // Nが非0だとすると derived(int x) : base1(x) {}; derived(int x, int y) : base2(x, y) {}; // error! 基底クラスはbase1 このように基底クラスをテンプレートで替える場合に、うまく派生クラスのコンストラクタの 引数の数を調整するようなテクニックがあれば、ご教示いただけると幸いです。 また、異なるアプローチもあればコメントください。
732 名前:デフォルトの名無しさん mailto:sage [2005/07/08(金) 20:50:10 ] 俺にはderivedをNの値によって特殊化する方法しか思いつかない。
733 名前:デフォルトの名無しさん mailto:sage [2005/07/08(金) 22:22:17 ] 試しにこう書いてみたら g++ 3.4.4 cygming special では通ったんだが。 derived(int x) : IF<N,base1,base2>::type(x) {} derived(int x, int y) : IF<N,base1,base2>::type(x,y) {}
734 名前:731 mailto:sage [2005/07/09(土) 02:41:09 ] >>732-733 レスありがとうございました。 >733の方法で、パパ、うまくできそうです。 続きがんばります!
735 名前:デフォルトの名無しさん mailto:sage [2005/07/09(土) 08:17:21 ] どうもネットの世界の「ご教示」とか「ご教授」って浮いた言葉だなぁ。
736 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 00:59:18 ] 実は初めてこの構文を知ったんだけどさ >ttp://www.comeaucomputing.com/techtalk/templates/#esprobs > >template <class T> >T foo(T blah) >{ > xyz object; > T someInt; > >// (略) > > someInt = object.mt<int>(99.99); // AA: ill-formed > someInt = object.template mt<int>(99.99); // BB: well-formed > > return someInt; >} ってなってて AA は ill-formed になってるんだけど、 object はテンプレートパラメータに依存してないんだから template をつけなくても問題ないと思うんだけど。実際 g++ 3.4.4 だと通るし、. の前をテンプレートパラメータに 依存するように書き換えるとエラーが出る。 規格参照箇所 14.2-4 > When the name of a member template specialization appears after . or -> in a postfix-expression, or after > nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a > template-parameter (14.6.2), the member template name must be prefixed by the keyword template. > Otherwise the name is assumed to name a non-template.
737 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 02:07:52 ] template <typename T> class Hoge { public: typedef std::vector<T> Container; typedef Container::iterator Iterator; private: Container v; }; と書いて、Hoge<int> hoge; とか呼ぶと、implicitなtypenameだと警告を言われます。 iteratorを表現するにはどのように記述すべきなのでしょうか。
738 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 02:09:19 ] >>737 gcc version 3.2 20020927 (prerelease) です。
739 名前:737 mailto:sage [2005/07/10(日) 02:11:47 ] www.tietew.jp/cppll/archive/10073 によると、 typename Container::iterator Iterator; と書くみたいですね。これって常識なのかしら。
740 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 02:27:11 ] >>739 その場合、typenameは必須。
741 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 02:36:16 ] 常識
742 名前:デフォルトの名無しさん mailto:sage [2005/07/10(日) 04:36:52 ] 当然
743 名前:デフォルトの名無しさん mailto:sage [2005/07/11(月) 10:24:40 ] >>739 特殊化があるC++では、Tが確定しないと型推論が困っちゃうんで、 typedef typename Container::iterator Iterator; って感じで。 typename Container::iterator Iterator; も可能。 Container<int> v; なら何とかなるはずだけど、explicitにtypenameしましょうという仕様。
744 名前:デフォルトの名無しさん mailto:sage [2005/07/16(土) 20:53:42 ] >型推論が困っちゃう そうなのか? Tが確定しないと、特殊化のあるC++ではstd::vector<T>::iteratorが typedefされた型名か、メンバ(メンバ変数・関数)かが分からないから コンパイラへのヒントとして型名であることを明示するのを義務付けてるんでは?
745 名前:デフォルトの名無しさん [2005/07/19(火) 22:11:08 ] 全然わかってないけど質問します。 テンプレートクラスの実装って全てヘッダーでやらないといけないんですか? .cppの方でやるとリンカーエラーが出てリンクできないのですが!? (全部ヘッダーにコピペしたら通った)
746 名前:デフォルトの名無しさん mailto:sage [2005/07/19(火) 22:14:53 ] 追加 だが、しかしそれをやると2重定義になる… どうすればいいんじゃーーーー
747 名前:デフォルトの名無しさん mailto:sage [2005/07/19(火) 22:20:05 ] >>745 テンプレートの定義をcppファイルに書きたければ、宣言と定義の両方にexportを付けるだけ。 しかしほとんどのコンパイラで使えない。(使えるコンパイラが全くないわけではない) というわけで普通はヘッダにインラインで全て書く。 ごく稀に明示的実体化が使われることはあるが。
748 名前:デフォルトの名無しさん mailto:sage [2005/07/19(火) 22:48:35 ] >>747 明示的実体化ってまさか、 template class c<bool>; template class c<char>; template class c<unsigned char>; みたいに延々と cpp ファイルに書いていくわけ?
749 名前:デフォルトの名無しさん mailto:sage [2005/07/19(火) 23:06:05 ] g++にはextern templateってのがあるね。
750 名前:デフォルトの名無しさん mailto:sage [2005/07/19(火) 23:11:50 ] >748 そゆこと。
751 名前:745 mailto:sage [2005/07/19(火) 23:17:21 ] やってみた>>747 make -k all g++ -Wall main.cpp Class.cpp -c g++ -Wall main.o Class.o -o a.exe main.o(.text+0x25):main.cpp: undefined reference to `Class<int>::Class[in-charge]()' collect2: ld returned 1 exit status make: *** [all] Error 1 ムリポ >>749 を含めて出直してくる。これはイマの私の頭ではいくら考えても答えが出ない。 本を読むかg++のマニュアルを漁るか…