我有一些 C++ 代码在没有 -fpermissive 选项的情况下不再编译。 这是我不能分享的专有代码,但我认为我已经能够提取一个简单的测试用例来证明这个问题。这是 g++ 的输出
template_eg.cpp: In instantiation of 'void Special_List<T>::do_other_stuff(T*) [with T = int]':
template_eg.cpp:27:35: required from here
template_eg.cpp:18:25: error: 'next' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
template_eg.cpp:18:25: note: declarations in dependent base 'List<int>' are not found by unqualified lookup
template_eg.cpp:18:25: note: use 'this->next' instead
所以这是产生问题的代码:
template<class T> class List
{
public:
void next(T*){
cout<<"Doing some stuff"<<endl;
}
};
template<class T> class Special_List: public List<T>
{
public:
void do_other_stuff(T* item){
next(item);
}
};
int main(int argc, char *argv[])
{
Special_List<int> b;
int test_int = 3;
b.do_other_stuff(&test_int);
}
我并不是想找出如何修复代码以使其再次编译。 这只是将 next(item) 更改为 this->next(item) 的问题 我试图更好地理解为什么这种改变是必要的。 我在此页面上找到了解释:http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html 虽然这个解释很有用,但我仍然有一些问题。我的函数采用 T*(指向类型 T 的指针)这一事实不应该使它依赖于模板参数。 用我自己的话说,编译器(gcc 4.7)不应该能够找出 next() 函数在基类 List 中吗? 为什么有必要在每个这样的调用前面加上 this->? 我注意到 clang 3.1 表现出相同的行为,所以我假设 c++ 标准中有一些要求需要这种行为。任何人都可以为此提供理由吗?
最佳答案
问题在于模板是分两次处理的(根据标准,VS 不这样做)。在第一遍中,在类型替换之前,查找并检查不依赖于模板参数的所有内容。一旦类型被替换,从属名称将在第二遍中解析。
现在,在第一遍中,没有任何内容表明 next
依赖于模板参数,因此它需要在类型替换之前解析。现在,因为基本类型是在当前模板的模板参数上模板化的,编译器无法查看它(它可能专门用于某些类型,并且不知道我们正在用什么类型 T
实例化模板,我们无法知道使用哪个特化,即基础 取决于 T
并且我们在知道 T
之前正在检查)。
添加 this->
的技巧转 next
成一个从属名称,这反过来意味着查找被延迟到第二遍,其中T
是已知的,并且因为 T
已知,List<T>
也是已知的,可以查到。
编辑:上述答案的措辞中缺少的一个重要细节是第二阶段查找(在类型替换之后)只会添加在参数相关查找期间找到的函数。也就是说,如果 next
是与 T
关联的命名空间中的自由函数它会被发现,但它是基础上的成员,对于 T
上的 ADL 不可见.
关于c++ - C++ 模板中的名称查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10639053/