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

时间:2015-10-30 11:10:09

标签: c++ templates language-lawyer instantiation

我不明白为什么它不正确

#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)都会出错。这种行为的原因是什么?

1 个答案:

答案 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外可见)。