2007-10-01
■[c++][2ch]c++スレより 「クラスの内側で定義したクラステンプレートを特殊化する」
何の気なくのぞいてみたら、2chって宝の山なのですね。
過去スレとかにも面白い書き込みがたくさんあり、幾つかがdatに行く前にこうやって張れたらと思います。
91 名前: デフォルトの名無しさん 投稿日: 2007/09/30(日) 20:19:13
クラスの内側で定義したクラステンプレートを特殊化する、
class X { template<typename T> class Y {}; template<> class Y<int> {}; };のようなコードは、VC++(2003/2005)ではコンパイルできますが、g++3/4では
error: explicit specialization in non-namespace scope ‘class X’ というエラー
になってしまいます。
Y<int>をXの中ではなく、名前空間スコープで
template<> class X::Y<int> {};
と書けばg++でもVC++でも問題なく特殊化できることは知っているのですが、
なんとかg++で、特殊化されたクラスの定義をXの中に書く方法はないでしょうか?
Y<T>とY<int>の定義が離れた場所にあると、コードが読みにくいと思うのです。
よろしくおねがいします。
93 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 20:42:48
>>91
定義位置を近づけたいなら、両方クラス外に書けばいいんじゃね?
94 名前: 91 投稿日: 2007/09/30(日) 20:45:33 >>93
ああ、たしかにそうですね。他に案がなければそうしたいとおもいます。
ただ、Y<T>とY<int>を両方クラス内に書けると、宣言と定義の位置も離れない(定義だけになる)ので、
より読みやすいと思っています。
というわけで、引き続きお願いします。
95 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 20:54:22
>>91
規格ではネストされたクラス内での明示的特殊化は禁止されているけど
部分特殊化はOKなので、
class X { template <typename T, class U = void> class Y {}; template <typename T> class Y< T , typename boost::enable_if< typename boost::is_same< T, int> > > {}; };のようにenable_ifとis_sameを使って書くといいっぽい(初心者スレから一部拝借w)
VCでコンパイル可能なのはmsの独自拡張でgccの方が正しいとのこと
96 名前: 91 投稿日: 2007/09/30(日) 20:57:38
なお、メンバ関数テンプレートで同様のエラーをくらう件については
(下記の2行めがエラーになる)、
class X { template<typename T> void foo(T x) {} template<> void foo<int>(int x) {} // error };下記方法でごまかしています。
#include <boost/type.hpp> class X { void foo_(int x, boost::type<int>) { /* specialized */ } template<typename T> void foo_(T x, ...) {} public: template<typename T> void foo(T x) { foo_(x, boost::type<T>()) ;} };
97 名前: 91 [sage] 投稿日: 2007/09/30(日) 20:59:12
>>95
部分特殊化はOKだったんですか。気づきませんでした。
早速試してみます。どうもありがとう〜!!
98 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 21:00:46
>>91
私はC++初心者ですが、>>93さんと同意見です。
>>95さんの言うようにgccの方が正しい(つまり規格どおりということですよね)ならば、
なおさらそう思います。
それに、Xクラスの定義を見たいときには、むしろYは外にあった方が見やすいのではないでしょうか?
99 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 21:06:58
この手法も名前があったと思うけど思い出せない
使うなら適当にローカルなメタ関数を専用の名前空間に自作して階層を浅くする工夫が必要だね
使ってればわかるけど、凄く見にくくなるから
100 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 21:10:12
あ、::type付けわすれた…
102 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 22:00:44
>>98 >>101
読みやすいかどうかは読み手にもよるし、あまり>>91や>>94はよい聞きかたではなかったですね。
C++のコードを自動生成するツール(自作)の都合でX内に定義を書けると嬉しい、というのが実際の事情です。
103 名前: 91 [sage] 投稿日: 2007/09/30(日) 22:32:03
102は91です。
>>99
concept-controlled polymorphism ですか?
104 名前: デフォルトの名無しさん 投稿日: 2007/09/30(日) 23:06:47
>>100
> あ、::type付けわすれた…
検索エンジン経由で来るひとのために、一応訂正版貼っときますね。
#include <cstdio> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_same.hpp> struct X { template<typename T, typename U = void> struct Y { Y() { std::printf("genecic\n"); } }; template<typename T> struct Y <T, typename boost::enable_if<boost::is_same<T, int> >::type> { Y() { std::printf("specialized for int\n"); } }; }; class Z {}; int main() { X::Y<Z> a; X::Y<int> b; X::Y<float> c; }実行結果は、
genecic
specialized for int
genecic
です。
105 名前: 91=104 [sage] 投稿日: 2007/09/30(日) 23:31:30
boostが使えない場合は、VC++2003/2005/g++対応だけ考えるならこんな感じでしょうか。
#include <cstdio> namespace b00st { template <bool B, class T = void> struct enable_if_c { typedef T type; }; template <class T> struct enable_if_c<false, T> { /* NO TYPEDEF! */ }; template <class Cond, class T = void> struct enable_if : public enable_if_c<Cond::value, T> {}; template<bool b> struct bool_ { static const bool value = b; }; template<typename T, typename U> struct is_same : bool_<false> {}; template<typename T> struct is_same<T, T> : bool_<true> {}; } using namespace b00st; struct X { template<typename T, typename U = void> struct Y { Y() { std::printf("genecic\n"); } }; template<typename T> struct Y<T, typename enable_if<is_same<T, int> >::type> { Y() { std::printf("specialized for int\n"); } }; };そろそろウザいとおもうので、これで打ち止めにします。ありがとうございました。
106 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/30(日) 23:40:10
このtemplate感、実に小気味良い 久しぶりにC++スレを実感した