模板特化在其实例化点看不到函数
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).
我不明白为什么它不正确
#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).