首页 文章

模板特化在其实例化中没有看到函数

提问于
浏览
4

我不明白为什么不正确

#include <iostream>
using namespace std;

struct CL{};

template <typename T>
void fnc(T t)
{
    f(t);
}

namespace NS {
    void f(CL){}
    void fn() {fnc(CL()); /*error is here*/}
    //point of instantiation fnc<CL> is here (in namespace scope,
    //according to 14.6.4.1/1)
}

int main(){}

在模板函数 fnc 中调用 f(t) 取决于模板参数,然后名称查找必须位于实例化点 . 我看到标准(C 14)14.6.4.1/1

对于函数模板特化,成员函数模板特化,或成员函数或类模板的静态数据成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化和其中的上下文中引用的引用取决于模板参数,专门化的实例化点是封闭专门化的实例化点 . 否则,这种特化的实例化点紧跟在引用特化的命名空间范围声明或定义之后 .

f(CL)fnc<CL> 实例化时可见,但所有编译器(VS,gcc,clang)都会出错 . 这种行为的原因是什么?

1 回答

  • 7

    这里 fnc 的参数 t 是一个从属名称,在解析模板时无法解析 . 相反,它们在实例化时再次被查找 . 这就是所谓的两阶段查找:第一阶段是解析模板,第二阶段是实例化 .

    您的问题的答案在于,在POI(实例化点)执行的第二次查找仅为 ADL . 由于struct CL 未在 void f(CL) 的同一名称空间内定义,因此POI查找不会发生,也不会找到它 .

    如果您尝试将struct CL 的定义放入命名空间以使ADL生效,它将很好地编译 .

    namespace NS {
        struct CL{};
        void f(CL){}
        //...
    }
    

    根据unqualified name lookup的规则,(由我粗体)

    对于模板定义中使用的从属名称,查询将被推迟,直到模板参数已知,此时ADL检查具有外部链接(直到C 11)的函数声明,这些声明从模板定义上下文以及模板实例化上下文,而非ADL查找仅检查具有从模板定义上下文可见的外部链接(直到C 11)的函数声明(换句话说,在模板定义之后添加新函数声明除了通过ADL之外不会使其可见) .

相关问题