C++テンプレートクラス内のメソッドを実装ファイルで定義する方法

このQ&Aのポイント
  • C++のテンプレートクラス内で入れ子クラスのメソッドを実装ファイルに定義する方法について教えてください。
  • 現在、テンプレートクラス内の入れ子クラスのコンストラクタを宣言のみにしていますが、別途実装ファイルに定義したいと考えています。
  • しかし、メソッドのシグネチャの書き方が分からず困っています。どのように書けば良いのでしょうか?環境はVC7.1かVC8です。
回答を見る
  • ベストアンサー

テンプレートクラス内のテンプレートクラス(インナークラス)のメソッドを実装ファイルで定義したい

現在、ヘッダファイル内で下記のようなクラスを宣言・定義しています。 // test.h template < typename T1 > struct A {   template < typename T2 > struct B   {     B( A const& arg ) { ... }   }; }; テンプレートクラスが入れ子になっていて、Bのコンストラクタが引数としてAを取っています。 しかし現状ではコンパイルがとんでもなく遅くなってしまうので、 Bのコンストラクタは宣言のみとし、別途実装ファイル(test.cpp)に定義を書きたいと思っています。 ところがメソッドのシグネチャをどう書けばよいのか分からなくなってしまいました。 苦し紛れに // test.cpp template < typename T1, typename T2 > A<T1>::B<T2>::B( A<T1> const& arg ) { ... } などと書いてみましたが、違うようです。 解決方法はありますでしょうか? 環境はVC7.1かVC8でコンパイルできればよいです。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

template < typename T1 > struct A {  template < typename T2 >  struct B {   B( A const& arg );  }; }; template<typename T1> template<typename T2> A<T1>::B<T2>::B( A<T1> const& arg ) { } int main() {  A<int> a;  A<int>::B<char> c(a); }

fioletti
質問者

お礼

epistemeさん、動きました。 こんな書き方があったのかと思い調べたところ、 C++Primer3版p880に説明を見つけることができました。 メンバテンプレートの外部定義というんですね。 今回はたいへん勉強になりました。ありがとうございます。

関連するQ&A

  • C++テンプレートクラスの内部クラスについて

    テンプレートクラスについていろいろ試していたところ以下のようなコードで struct A {     struct AA { };     operator A::AA() { return A::AA(); } // (1) }; template<typename T> struct B {     struct BB { };     template<typename U>     operator B<U>() { return B<U>(); } // (2)     template<typename U>     operator typename B<U>::BB() { return typename B<U>::BB(); } // (3) }; int main() {     static_cast<A::AA>(A()); // (1) ok     static_cast<B<int> >(B<short>()); // (2) ok     static_cast<B<int>::BB>(B<short>()); // (3) compile error     return 0; } (1)と(2)はできて(3)だけがコンパイルを通りませんでした。 試したコンパイラはVC9とg++(3.3.4)とbcc32(5.5.1)で、VC9では以下のようなエラーをはきました。 「error C2440: 'static_cast' : 'B<T>' から 'B<T>::BB' に変換できません。     with [ T=short ] and [ T=int ] コンストラクタはソース型を持てません、またはコンストラクタのオーバーロードの解決があいまいです。」 (1)と(2)ができれば(3)のようなこともできそうな感じがしたのですが、他に書き方があるのでしょうか。 どなたかご存知の方がいらっしゃいましたらご教示お願いします。

  • templateの抽象クラスについて

    VC++2003の環境なんですが、 下記の状態でtest2.a()を呼び出すと未解決の外部シンボル(LNK2019)のエラーが発生します。同じファイルでこれらを定義した場合は普通に通りました。class内で定義した場合も通ります。なぜでしょうか? test1.h : template<class T> class test1 { public: void a(); }; test1.cpp : template <class T> void test1<T>::a(){} test2.cpp : class test2 : public test1<int> {public:};

  • C++ テンプレートクラス内のメソッド 警告 意味

    VC++2008 windows7 の環境でC++のプログラミングをしております. 以下の種類の警告がいくつか出てくるのですが,この警告の理由が分かる方いますか? 実行結果には影響は出ていませんが,出来れば消したいと考えています. クラス テンプレート のメンバ関数 void A<T>::TEST(A<T> *,int) のコンパイル中 1> .\main.cpp(69) : コンパイルされたクラスの テンプレート のインスタンス化 1> 'A<T>' の参照を確認してください 1> with 1> [ 1> T=uchar 1> ]

  • 外部ファイルでのtemplate関数の実装方法

    外部ファイルでのtemplate関数の実装方法 sub.cppにtemplate関数を実装し、 main.cppで、sub.cppのtemplate関数を呼び出す、 みたいなことをやりたいのですが、 コンパイルは通りますが、リンクエラー?になってしまいます。 以下が上記のサンプルプログラムです。 //main.cpp #include <vector> #include <iostream> using namespace std; template <typename t_ret, typename t_array> t_ret sub_t(const t_array&); int main (int argc, char *argv[]) { vector<double> v; v.push_back(1.1); v.push_back(2.2); cout << sub_t<double, vector<double> >(v) << endl; return 0; } // sub.cpp #include <vector> using namespace std; template <typename t_ret, typename t_array> t_ret sub_t(const t_array& array) { return array[0]+array[1]; } //コンパイルログ main.o: In function `main': main.cpp:(.text+0x134): undefined reference to `double sub_t<double, std::vector<double, std::allocator<double> > >(std::vector<double, std::allocator<double> > const&)' collect2: ld returned 1 exit status make: *** [main] Error 1 どなたか、対処方法を教えてください。 宜しくお願いします。

  • テンプレートクラス中のフレンドクラス

    下記をg++(fedora core1)でコンパイルしたところ、 #include <iostream> using namespace std; template< typename T > class A {   T a; public:   A(T aa ) : a(aa) { }   friend ostream& operator<<( ostream &os, const A &a ); //9行目 }; template< typename T > ostream& operator<<( ostream &os, const A<T> &a ) { return os << a.a; } int main( ) {   A<int>  a(5);   cout << a << '\n';   return 0; } 9行目にこのような警告・エラーが出てコンパイルできませんでした。(下記のオプションも試してみましたがダメでした) friend declaration 'std::ostream& operator<<(std::ostream&, const A<T>&)' declares a non-template function (if this is not what you intended, make sure the function template has already been declared and add<> after the function name here) -Wno-non-template-friend disables this warning. :undefined reference to 'operator<<(std::basic_ostream <char, std::char_traits<char> >&, A<int> const&)' なぜ、コンパイルできないのかが分かりません。ちなみに、bcc32(borland c++ compiler5.5.1)では同様のエラーが出てコンパイルできず、cl(VC++6.0)ではコンパイル・実行可能でした。 ご存知の方いらっしゃったらご教授お願いします。(bccとclはWinXPです)

  • C++のtemplateクラス前方宣言について教えてください

    C++で、以下のようなコードを書いたのですがコンパイルが通りません。 どのようにコードを修正すればコンパイルを通すことができるでしょうか??教えてください。 template <class _T> class Test; // 上をclass Test<_T>にしてもコンパイルは通りません void main() {   Test<int> hoge; } template <class _T> class Test { public:   _T val;   Test():val(0){}; }; /*! エラー内容: 前方宣言class Test;の場合 'hoge'が未定義のclass'Test<_T>'で使用しています。   with   {     _T=int   } 前方宣言class Test<_T>;の場合 構文エラー:';'が'<'の前にありません。 構文エラー:'<' 'hoge'が未定義のclass 'Test<_T>'で使用しています。 */ 開発環境: VisualStudio2005 AcademicEdition WindowsXP Professional メモリ:2048MB CPU:Core2Duo 1.33GHz よろしくお願いします。

  • C++ のクラスの定義

    C++の初心者です。 C++のことでお聞きしたいことがあります。 namespace test1{ class A { friend class B; protected: int a; }; } とtest1の下にAクラスを作り namespace test2{ class B { public: test1::A A1; }; } と別のnamespaceにBというクラスを作り、 A1というAのインスタンスを持ちたいのです。 しかし、Aというクラスを先に宣言しているので Bというクラスが解らないらしく friendがうまく働きません。 friend class test2::B としても test2がまだ宣言されていないので、 ????とコンパイルエラーが出ます。 先にtest2::B を宣言してしまうと、 今度はtest1::Aが解らずに エラーが出てしまいます。 こんな場合はどのように書けばよろしいのでしょうか? 環境はwindows2000でVC++ 6.0です。 どうか宜しくお願いいたします。

  • テンプレートが複雑すぎる?

    以下のような文字列比較関数を作ろうと思っています。 ○配列変数であるときは配列版を、そうでないときはポインタ版を呼び出す  配列のサイズがわかるときは、仮に\0で終端していなくてもそれ以上検索しない ○charかwchar_tかを意識せずに使える ○charとwchar_tという記述ではなく、templateでできるだけジェネリック?的に記述したい //charを入れるとwchar_t、wchar_tを入れるとcharを返すメタ関数 template<typename T> struct invert{}; template<> struct invert<char>{ typedef wchar_t t; }; template<> struct invert<wchar_t>{ typedef char t; }; //同じ型同士の比較は省略 //A: 両方ポインタ template<typename T> bool compare(const T *const &v1, const typename invert<T>::t *const &v2); //B1: 左がポインタ、右が配列 template<typename T, size_t L> bool compare(const T *const &v1, const typename invert<T>::t (&v2)[L]); //B2: Tとtypename invert<T>::tを逆に template<typename T, size_t L> bool compare(const typename invert<T>::t *const &v1, const T (&v2)[L]); //C: 左が配列、右がポインタ //省略 //D: 両方配列 template<typename T, size_t L1, size_t L2> bool compare(const T (&v1)[L1], const typename invert<T>::t (&v2)[L2]); char aa[] = "abc"; char *pa = aa; wchar_t aw[] = L"abc"; wchar_t *pw = aw; bool c1 = compare(pa, pw); //A bool c2 = compare(pa, aw); //B1はC2784, B2なら可 bool c3 = compare(aa, pw); //C bool c4 = compare(aa, aw); //DはC2784 invert<T>::t (&v2)[L]という記述が複雑?なのかB1は呼べず、B2と記述すると通りました。 しかしDはどちらも配列であるため、B2のように回避できません。 オーバーロードを全て記述せずに、できるだけ簡単にすます方法はありませんか? 環境はVC++2010です。

  • デフォルトコンストラクタで分からないことがあります。

    デフォルトコンストラクタ デフォルトコンストラクタで分からないことがあります。 以下のコードです。 > template<class T1, class T2> > struct pair > { > T1 first; // 1つ目の値 > T2 second; // 2つ目の値 > > // デフォルトコンストラクタ > pair() : first( T1() ), second( T2() ){} > > // 引数付きコンストラクタ > pair(const T1& a, const T2& b) : first( a ), second( b ){} > }; このコードの中の pair() : first( T1() ), second( T2() ){} で初期化子による初期化をしていると思うのですが「T1()」と「T2()」は具体的に 何をしているのでしょうか?自分の想像ではfirstとsecondに何か初期化の値を代入して初期化していると思うのですが何でしょうか? なお、その次のコードの意味は分かります。 > pair(const T1& a, const T2& b) : first( a ), second( b ){} これは、引数a,bを持っていてそれぞれfirstにaを代入してsecondにbを代入して初期化しているのですよね。 なお、このコードが掲載されているサイトはここです。 http://www.geocities.jp/ky_webid/cpp/library/011.html

  • templateクラスについて

    先ほど以下のようなプログラムを書いたのですがコンパイルを通すことができません。 //適当なポインタを保持するだけのクラス template <class _type> class hoge { private:   //適当に変数を保持   _type val; public:   //コンストラクタで適当に値をセット   hoge() : val( 0 ){}   //このクラスから唯一ポインタを引っ張ってくる方法   friend _type getVal( const hoge& foo )   {     // そのまま返す     return foo.val;   } }; void func( const hoge<int>& foo ) {   //値を引き出す   getVal( foo ); } void main() {   //実体化   hoge<int> foo;   //値を引き出す   getVal( foo );   //関数の先で値を引き出す   func( foo ); } 上記のようなプログラムを書いたのですが、main関数内でgetValを呼び出す場合はとくに問題ないのですがfunc関数を呼び出してfunc関数内でgetValを呼び出すと error C3861: 'getVal': 識別子が見つかりませんでした error C2365: 'getVal' : 再定義; 以前の定義は '以前は不明な識別子' でした。 コンパイルされたクラスの テンプレート のインスタンス化 'hoge<_type>' の参照を確認してください というエラーが出てしまいます。 func関数の引数を( const hoge<int>& foo )からvoid func( hoge<int> foo )のように参照渡しから実体渡しに変更するとコンパイルが通り、実行もできるのですが、なぜこれでコンパイルが通るのか理由がいまいちよくわかりません。 またやはり、コンストラクタ、デストラクタの問題などから実体渡しより、参照渡しを使いたいのですがどのようにプログラムを書けば今回の問題を解決できますでしょうか。 よろしくおねがいします。 /* VisualStudio2005 AcademicEdition MicroSoft WindowsXP Professional 32bit */