c++ - C++ 模板中的名称查找

标签 c++ templates inheritance

我有一些 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/

相关文章:

c++ - 为什么不允许非静态成员的地址作为模板非类型参数?

c# - 类中的组方法

inheritance - 使用 swift 在子类中设置基类 'let' 变量

c++ - 用编译时生成的随机 ID 替换魔法 ID 号

c# - c#中使用了pimpl成语吗?

c++ - 如何在动态数组中的某些对象上调用析构函数

javascript - Meteor JS - 如何将服务器方法与模板中进行的某些操作连接起来?

javascript - JavaScript:对象继承自Function.prototype

c++ - makefile 中的条件变量

c++ - 无法将简单的读/写串行端口代码从 boost::asio::serial_port 迁移到 QSerialPort