Hatena::Diary

matsutakegohan1の日記

2007-10-01

[][]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 scopeclass X’ というエラー

になってしまいます。

Y<int>をXの中ではなく、名前空間スコープで

template<> class X::Y<int> {};

と書けばg++でもVC++でも問題なく特殊化できることは知っているのですが、

なんとかg++で、特殊化されたクラスの定義をXの中に書く方法はないでしょうか?

Y<T>とY<int>の定義が離れた場所にあると、コードが読みにくいと思うのです。

boost(特にmpl)の使用は歓迎です。

よろしくおねがいします。

 

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++スレを実感した

トラックバック - http://d.hatena.ne.jp/matsutakegohan1/20071001/1191245392