Ava*_*r33 39 c++ inheritance templates
我有一些不使用-fpermissive选项而不再编译的C++代码.这是我不能分享的专有代码,但我认为我已经能够提取一个简单的测试用例来证明这个问题.这是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
Run Code Online (Sandbox Code Playgroud)
所以这是产生问题的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
我不是要找出如何修复代码以使其再次编译.这只是将下一个(项目)改为此 - >下一个(项目)的问题我正在努力更好地理解为什么这种改变是必要的.我在这个页面上找到了一个解释:http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html 虽然这个解释很有用,但我还是有一些问题.不应该我的函数采用T*(指向类型T的指针)的事实使它依赖于模板参数.在我自己的措辞中,编译器(gcc 4.7)是否应该能够找出next()函数在基类List中?为什么有必要在每次这样的呼叫前面加上这个?>?我注意到clang 3.1表现出相同的行为,所以我假设c ++标准中有一些要求这种行为的要求.任何人都可以为它提供理由吗?
Dav*_*eas 57
问题是模板经过两次处理(根据标准,否则VS).在第一遍中,在类型替换之前,查找并检查不依赖于模板参数的所有内容.一旦类型被替换,依赖名称将在第二遍中解析.
现在,在第一遍中没有任何东西表明它next
依赖于模板参数,因此它需要在类型替换之前解析.现在,因为基类型是在当前模板的模板参数上模板化的,所以编译器无法查看它(它可能专门用于某些类型,并且不知道T
我们用什么类型实例化模板,我们无法知道哪个特化到使用,即基本依赖于T
我们知道之前检查T
).
加入的特技this->
变成next
为从属的名字,而这又意味着,查找被延迟直到第二遍中,其中T
已知的,并且因为T
是已知的,List<T>
还已知并可以查找到.
编辑:上面答案的措辞中缺少的一个重要细节是第二阶段查找(在类型替换之后)将仅添加在参数依赖查找期间找到的函数.也就是说,如果找到next
与其关联的命名空间中的自由函数T
,但它是基础上的成员,对于ADL而言是不可见的T
.
Naw*_*waz 10
你需要写作this->
:
this->next(item);
Run Code Online (Sandbox Code Playgroud)
这里this->
部分是必需的,因为它next()
是模板库中的继承成员,如果您仔细阅读错误消息,则会自行建议:
template_eg.cpp:18:25:注意:
'List<int>'
非限定查找
template_eg.cpp 找不到依赖库中的声明:18:25:注意:改为使用'this->next'
阅读本文介绍了C++中的两阶段名称查找:
如果你的基类是一个模板实例,那么就没有办法知道它next
引用了基类中的名字 - 毕竟,名称甚至不需要存在(想想专业化)!因此,你必须要断言编译器next
实际上是说一个类的成员this->
,或者List<T>::next
,或者通过预先using List<T>::next;
给你的派生类的模板.