我不明白为什么它不正确
#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(){}
在模板函数f(t)
中调用fnc
取决于模板参数,然后名称查找必须位于实例化点。我看到标准(C ++ 14)14.6.4.1/1
对于函数模板特化,成员函数模板 专业化,或成员函数或静态的专业化 如果专门化是隐式的,则为类模板的数据成员 实例化,因为它是从另一个模板中引用的 专业化和引用它的上下文取决于 在模板参数上,实例化的点 专业化是封闭的实例化点 专业化。 否则,这样的实例化点 特殊化紧跟在命名空间范围声明之后 引用专业化的定义。
f(CL)
在fnc<CL>
的实例化时可见,但所有编译器(VS,gcc,clang)都会出错。这种行为的原因是什么?
答案 0 :(得分:7)
此处t
的参数fnc
是一个从属名称,在解析模板时无法解析。相反,它们在实例化时再次被查找。这就是所谓的两阶段查找:第一阶段是解析模板,第二阶段是实例化。
您的问题的答案在于,在POI(实例化点)执行的第二次查找仅是 ADL 。由于结构CL
未在void f(CL)
的同一名称空间内定义,因此POI查找不会发生,也不会找到它。
如果您尝试将结构CL
的定义放入命名空间以使ADL生效,它将很好地编译。
namespace NS {
struct CL{};
void f(CL){}
//...
}
根据unqualified name lookup的规则,(由我加粗)
对于模板定义中使用的从属名称,查找为 推迟到模板参数已知,此时ADL 用外部链接检查函数声明(直到C ++ 11) 从模板定义上下文以及中可见 模板实例化上下文,而非ADL查找仅检查 具有外部链接的函数声明(直到C ++ 11) 从模板定义上下文中可见(换句话说,添加 模板定义后没有新的函数声明 除ADL外可见)。