2009-12-09 93 views
23

剛纔我已經通過網站挖掘,找出爲何模板類模板成員函數是給語法錯誤:C++模板陷阱

template<class C> class F00 { 
    template<typename T> bar(); 
}; 
... 
Foo<C> f; 
f.bar<T>(); // syntax error here 

我現在認識到模板支架作爲關係運算處理。做的目的需要以下離奇的語法,CF Templates: template function not playing well with class's template member function

f.template bar<T>(); 

其他什麼離奇的方面和C++/C++,你可能遇到了沒有的東西,你會認爲是常識的模板的疑難雜症?

+0

順便說一句,你可能只想限制它到模板陷阱,對於一般的C++陷阱已經有另一個問題了。 – int3 2009-12-10 07:22:50

+2

'template bar();'有什麼返回類型? – xtofl 2009-12-10 07:58:48

+1

你錯了你的假設。這裏你不需要'template',因爲'f'不是一個獨立的名字。無論如何,它會依賴於什麼?這是一個未指定範圍的名稱,用於「Foo 」類型的對象。 – MSalters 2010-09-22 09:51:14

回答

8

這一個讓我心煩當時:

#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

有沒有海灣合作委員會的標誌,讓它警告這件事? (我敢打賭,有大約一百萬人......) – 2009-12-10 07:00:55

+0

咦?我不明白這對編譯器來說可能是模棱兩可的。 'f.'後的任何內容都必須是'foo'的成員,爲什麼它會找到'std :: vector'?有什麼情況可以讓你找到非會員? – 2011-07-24 16:45:43

+1

@彼得這與神祕的語境有關。在C++ 0x中不再存在在周圍範圍內查找'vector'的規則。它在現代C++ 03編譯器上也只產生警告(如果有任何消息的話)。例如,[請參閱此處的clang](http://clang.llvm.org/docs/UsersManual.html#opt_Wambiguous-member-template)。在'f'後面,下一個名字不一定是'foo'的成員。例如,考慮:struct A {void f(); }; struct B {typedef A type; }; int main(){A a; A·B ::類型:: F(); }'。 – 2011-07-24 16:53:55

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>是印度政府ng作爲默認模板或專門的模板。專用版本可能沒有int a作爲成員,因此編譯器不會假定它是可用的。但你可以告訴它要在那裏與using指令編譯器:

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

或者,你可以把它明確您所使用的T成員:

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

「編譯器不知道基地是否將成爲默認模板」:這是一個很好的解釋。請注意,使用基類成員變量是_actually_破解封裝,因此不鼓勵。 – xtofl 2009-12-10 08:05:40

+0

基類_methods_存在同樣的問題。問題發生在名稱查詢中,在這一點上,你甚至不知道你會找到什麼。 – MSalters 2010-09-22 09:53:19

4

超出範圍類成員函數定義如下:

template <typename T> 
class List {      // a namespace scope class template 
    public: 
    template <typename T2>  // a member function template 
    List (List<T2> const&);  // (constructor) 
    … 
}; 
template <typename T> 
template <typename T2> 
List<T>::List (List<T2> const& b) // an out-of-class member function 
{         // template definition 
    … 
} 
5

關於模板的問題的明星在SO上:缺少的類型名!

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關鍵字告訴他。

模板內部類或模板成員/靜態函數也是如此:它們必須使用template關鍵字進行消歧,如OP中所述。

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 
}