2009-12-09 12 views
23

はちょうど今、私は、テンプレートクラステンプレートのメンバ関数は、構文エラーを与えていた理由を見つけるためにウェブサイトを通じて掘っていた落とし穴。あなたは常識であることを検討するものではありませんでしたその遭遇した奇妙な他のC++テンプレートは

f.template bar<T>(); 

何側面およびC++/C++テンプレートの落とし穴:CF Templates: template function not playing well with class's template member function、以下の奇妙な構文が必要とされていることを意図した何をすべきか?

+0

Btwの場合は、テンプレートgotchasに限定したいと思うかもしれません。一般的なC++のgotchasについてもう一つの質問があります。 – int3

+2

'template bar();'にはどのような戻り値がありますか? – xtofl

+1

あなたはあなたの前提に間違いがあります。 'f'は従属名ではないので、ここで' template'は必要ありません。とにかくそれは何に依存するでしょうか?これは、 'Foo '型のオブジェクトに対して、不特定のスコープ内の名前です。 – MSalters

答えて

8

この1つは私が当時動揺しました:

#include <vector> 
using std::vector; 

struct foo { 
    template<typename U> 
    void vector(); 
}; 

int main() { 
    foo f; 
    f.vector<int>(); // ambiguous! 
} 

をコンパイラがfoovectorを検索しますが、また、main内から始まる非修飾名としてだけでなくので、メインの最後の行は、あいまいです。したがって、std::vectorfoo::vectorの両方が見つかります。

:これを修正するには、

f.foo::vector<int>(); 

GCCがその気に、かつ直感的なもの(メンバーを呼び出す)を行うことによって、上記のコードを受け入れていない、他のコンパイラがより良い行い、コモのような警告を記述する必要があります

"ComeauTest.c", line 13: warning: ambiguous class member reference -- function 
      template "foo::vector" (declared at line 8) used in preference to 
      class template "std::vector" (declared at line 163 of 
      "stl_vector.h") 
     f.vector<int>(); // ambiguous! 
+0

これについて警告するGCCフラグはありますか? (私はあることを賭ける、それらの約百万人がある...) –

+0

ああ?私はこれがどのようにコンパイラにとってあいまいであるのか理解していません。 'f.'の後のものは' foo'のメンバでなければなりません。なぜ 'std :: vector'が見つかるのですか?あなたが非会員を見つけることができるような状況はありますか? –

+1

@Peterそれはあいまいな言語の状況と関係があります。周囲のスコープ内でも 'vector'を参照するルールは、C++ 0xではもう存在しません。また、現代のC++ 03コンパイラでは警告メッセージ(メッセージがあれば)のみを出力します。たとえば、[clangについてはこちらをご覧ください](http://clang.llvm.org/docs/UsersManual.html#opt_Wambiguous-member-template)。 'f.'の後に、次の名前は必ずしも' foo'のメンバーではありません。たとえば、次のように考えてみましょう: 'struct A {void f(); }; struct B {typedef A型; }; int main(){A a; a.B :: type :: f(); } '。 –

14

私は、私は別のテンプレートクラスからテンプレートクラスを継承した最初の時間をつまずいてしまった:

template<typename T> 
class Base { 
    int a; 
}; 

template<typename T> 
class Derived : public Base<T> { 
    void func() { 
     a++; // error! 'a' has not been declared 
    } 
}; 

問題はBase<T>がGOIの場合、コンパイラが認識していないということですデフォルトのテンプレートまたは特殊なテンプレートにする。特殊バージョンは、メンバーとしてint aを持たないかもしれないので、コンパイラは利用可能であると想定しません。スコープのうち

void func { 
    T::a++; // OK! 
} 
+1

"Base がデフォルトのテンプレートになるかどうかコンパイラはわかりません。"基本クラスのメンバ変数を使用することは、実際にはカプセル化を破っていることに注意してください。 – xtofl

+0

基本クラス_methods_にも同じ問題があります。名前のルックアップで問題が発生しますが、その時点で何を見つけるか分からなくなります。 – MSalters

4

:あなたはTのメンバーを使用していることが明示的なことを確認することができ、また

template<typename T> 
class Derived : public Base<T> { 
    using Base<T>::a; 
    void func() { 
     a++; // OK! 
    } 
}; 

:しかし、あなたはusingディレクティブと一緒にそこになるだろうコンパイラに伝えることができますクラスメンバ関数の定義:

5

ここにテンプレートに関する質問:欠落している型名!

template <typename T> 
class vector 
{ 
    public: 
    typedef T * iterator; 
    ... 
}; 

template <typename T> 
void func() 
{ 
    vector<T>::iterator it;   // this is not correct! 

    typename vector<T>::iterator it2; // this is correct. 
} 

ここでの問題は、vector<T>::iteratorが依存名であるということである:それはテンプレートパラメータに依存します。結果として、コンパイラはiteratorが型を指定することを知らない。我々は彼にtypenameキーワードで伝える必要があります。

テンプレートの内部クラスまたはテンプレートメンバー/静的関数についても同じことが言えます.Opt31に記載されているように、templateキーワードを使用して曖昧さを除去する必要があります。

template <typename T> 
void func() 
{ 
    T::staticTemplateFunc<int>();   // ambiguous 

    T::template staticTemplateFunc<int>(); // ok 

    T t; 

    t.memberTemplateFunc<int>();   // ambiguous 

    t.template memberTemplateFunc<int>(); // ok 
}