c – 功能模板签名

是什么决定了两个函数模板声明是否声明了相同的模板,还是同名的重载?

答案的开头是在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不相同.

点赞