2009-12-09 172 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 
}