模板特化在其实例化点看不到函数

Template specialization doesn't see a function in its point of 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(){}

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

For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

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

这里fnc的参数t是依赖名,解析模板时无法解析。相反,它们会在实例化时再次查找。这就是所谓的两阶段查找:第一阶段是模板的解析,第二阶段是它的实例化。

您问题的答案在于,在 POI(实例化点)执行的第二次查找只是一个 ADL。由于结构 CL 未在与 void f(CL) 相同的命名空间内定义,因此不会进行 POI 查找,也不会找到它。

如果你尝试将结构CL的定义放入命名空间使ADL生效,它会编译好。

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

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

For a dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11) that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).