Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function template signatures

What determines whether two function template declarations declare the same template, or are overloads of the same name?

The beginning of the answer is found in 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.

The signature of a non-template non-member function is (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]

The parameter-type-list mentioned twice already is defined in section 8.3.5p5. The paragraph describes how the actual types of function parameters are adjusted from the declared types, replacing arrays and functions with pointers, and discarding top-level cv-qualifiers. Then,

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.

So in the non-template case, parameter-type-list is plainly a conceptual semantic list of types (plus maybe a fancy ending), not a sequence of tokens or syntactic construct. And the following is, as we'd expect, a violation of the ODR, since both definitions define the same function:

void f(int, int*) {}
void f(int p, decltype(p)*) {}

In the template case, we have (1.3.18):

signature

<function template> name, parameter type list (8.3.5), enclosing namespace (if any), return type, and template parameter list

Now consider:

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 version 4.6.3 complains that definitions #1 and #2 define the same function, but has no problem accepting #1 and #3 as overloads. (It also thinks #3 is more specialized than #1, and there's no way to call #1, but that's a tangent issue.) The main difference between #2 and #3 is that q is type-dependent and p is not. So I guess the meaning of decltype(q) can't be determined until the template is instantiated? Is this behavior guaranteed by the Standard?

For function templates, the meaning of parameter-type-list must be allowed to include template parameters which have not yet been replaced by instantiation, and therefore dependent names and all that. But that makes it tricky, if possible, to know whether two declarations are equivalent.

A similar issue is solved by 14.5.6.1 paragraphs 5-6, which define equivalent expressions and equivalent function template declarations (same sequence of tokens except that different declarations may use different identifiers for the template parameters), functionally equivalent expressions and functionally equivalent function template declarations (same after instantiation), with the requirement:

If a program contains declarations of function templates that are functionally equivalent but not equivalent, the program is ill-formed; no diagnostic is required.

An example from paragraph 5 demonstrates safely equivalent function templates:

template <int I, int J> void f(A<I+J>);  // #1
template <int K, int L> void f(A<K+L>);  // same as #1

and an example from paragraph 7 demonstrates a violation of that rule:

// 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>);

But this doesn't apply to the example g functions above. T* and decltype(q)* might be considered functionally equivalent under some analogous definition of equivalence of type, but section 14.5.6.1 only spells out replacement of expressions, not types.

like image 807
aschepler Avatar asked Nov 03 '22 06:11

aschepler


1 Answers

The Standard has a quiet not explicitly defined equivalence rule for types that is mainly based on syntax for qualified names but for template parameters is the position in the paremeter list and the nesting depth of that list (i.e whether it is the one of a member template or of the enclosing class template).

A particular dependent type is remembered by typedefs. However that decltype type by 14.4p2 is a distinct type and not equivalent with T.

like image 135
Johannes Schaub - litb Avatar answered Nov 09 '22 08:11

Johannes Schaub - litb