在C++模板中进行名称查找

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++中的两阶段名称查找:


Ker*_* SB 5

如果你的基类是一个模板实例,那么就没有办法知道它next引用了基类中的名字 - 毕竟,名称甚至不需要存在(想想专业化)!因此,必须要断言编译器next实际上是说一个类的成员this->,或者List<T>::next,或者通过预先using List<T>::next;给你的派生类的模板.