是什么决定了两个函数模板声明是否声明了相同的模板,还是同名的重载?
答案的开头是在3.5p9中找到的:
Two names that are the same (Clause 3) and that are declared in different scopes shall denote the same variable, function, type, enumerator, template or namespace if
both names have external linkage or else both names have internal linkage and are declared in the same translation unit; and
both names refer to members of the same namespace or to members, not by inheritance, of the same class; and
when both names denote functions, the parameter-type-lists of the functions (8.3.5) are identical; and
when both names denote function templates, the signatures (14.5.6.1) are the same.
非模板非成员函数的签名是(1.3.17):
signature
<function> name, parameter type list (8.3.5), and enclosing namespace (if any)
[Note: Signatures are used as a basis for name mangling and linking. — end note]
已提到两次的参数类型列表已在8.3.5p5节中定义.该段描述了如何从声明的类型调整实际类型的函数参数,用指针替换数组和函数,以及丢弃顶级cv限定符.然后,
The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function’s parameter-type-list.
所以在非模板的情况下,参数类型列表显然是类型的概念语义列表(加上可能是一个奇特的结尾),而不是一系列标记或句法结构.正如我们所期望的那样,以下是违反ODR的原因,因为两个定义都定义了相同的功能:
void f(int, int*) {}
void f(int p, decltype(p)*) {}
在模板的情况下,我们有(1.3.18):
signature
<function template> name, parameter type list (8.3.5), enclosing namespace (if any), return type, and template parameter list
现在考虑:
template<typename T> void g(int, int*, T, T*) {} // #1
// template<typename T> void g(int p, decltype(p)*, T, T*) {} // #2
template<typename T> void g(int, int*, T q, decltype(q)*) {} // #3
g -std = c 0x版本4.6.3抱怨定义#1和#2定义相同的函数,但是没有问题接受#1和#3作为重载. (它还认为#3比#1更专业,并且没有办法调用#1,但这是一个相切问题.)#2和#3之间的主要区别在于q依赖于类型而p不是.所以我想在模板实例化之前无法确定decltype(q)的含义?这种行为是否由标准保证?
对于函数模板,必须允许参数类型列表的含义包括尚未被实例化替换的模板参数,因此包括依赖名称和所有这些.但是,如果可能的话,这使得知道两个声明是否相同是很棘手的.
类似的问题由14.5.6.1段落5-6解决,它定义了等价表达式和等效函数模板声明(令牌的相同序列,除了不同的声明可能对模板参数使用不同的标识符),功能等效表达式和功能等效函数模板声明(在实例化后相同),具有以下要求:
If a program contains declarations of function templates that are functionally equivalent but not equivalent, the program is ill-formed; no diagnostic is required.
第5段中的示例演示了安全等效的函数模板:
template <int I, int J> void f(A<I+J>); // #1
template <int K, int L> void f(A<K+L>); // same as #1
而第7段中的一个例子表明违反了该规则:
// Ill-formed, no diagnostic required
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+1+2+3+4>);
但这不适用于上面的示例g函数.在类型等价的某些类似定义下,T *和decltype(q)*可能在功能上被认为是等价的,但是第14.5.6.1节只说明了表达式的替换,而不是类型.
最佳答案 标准有一个安静的未明确定义的类型等价规则,主要基于限定名称的语法,但模板参数是参数列表中的位置和该列表的嵌套深度(即它是否是成员模板之一或封闭的类模板).
typedef会记住特定的依赖类型.然而,14.4p2的decltype类型是一种独特的类型,与T不相同.