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

use*_*538 4 c++ templates instantiation language-lawyer

我不明白为什么不正确

#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(){}
Run Code Online (Sandbox Code Playgroud)

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

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

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

son*_*yao 7

这里的论点tfnc是一个从属名称,解析模板时,不能得到解决.相反,它们在实例化时再次被查找.这就是所谓的两阶段查找:第一阶段是解析模板,第二阶段是实例化.

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

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

namespace NS {
    struct CL{};
    void f(CL){}
    //...
}
Run Code Online (Sandbox Code Playgroud)

根据不合格名称查询的规则,(由我粗体)

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