是什么决定了两个函数模板声明是声明了同一个模板,还是同名的重载?
答案开头在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]
提到两次的parameter-type-list 已经在第 8.3.5p5 节中定义。该段描述了函数参数的实际类型如何根据声明的类型进行调整,用指针替换数组和函数,并丢弃顶级 cv-qualifiers。然后,
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.
因此,在非模板情况下,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
是类型-dependent 而 p
不是。所以我猜 decltype(q)
的含义在模板实例化之前无法确定?标准保证这种行为吗?
对于函数模板,必须允许parameter-type-list 的含义包括尚未被实例化替换的模板参数,以及相关名称和所有其他内容。但这使得了解两个声明是否等同变得棘手(如果可能的话)。
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。
关于c++ - 函数模板签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14420908/