Domanda

In the following,

int i{3};
const int j{3};
extern const int k{3};

template <typename T, T&>
void f() {}

int main()
{
    f<int, i>();        // OK
    f<int const, j>();  // not valid template argument: 'j' has not external linkage
    f<int const, k>();  // OK
}

GCC gives error for the use of j as template parameter, while clang compiles fine.

  • what is the linkage of i, j?
  • why is there a difference between const/non-const?
  • who is correct? GCC or clang?
È stato utile?

Soluzione

As Kerrek points out in the comment, namespace level const variables have internal linkage (unless you use the extern keyword). In C++03 you cannot use the a pointer or reference of a variable with internal linkage as a non-type template argument. That restriction was lifted in C++11. It seems that your version of gcc is playing by the C++03 rules, while the clang compiler is using the C++11 ones.


14.3.2 [temp.arg.nontype] / 1

A template-argument for a non-type, non-template template-parameter shall be one of:

  • [...]
  • a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or
  • [...]

Altri suggerimenti

i has external linkage while j has internal linkage. These rules are listed under §3.5 [basic.link]

4 An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
— a variable; or
— ...

The global namespace has external linkage, hence i has external linkage as well (since it's not explicitly declared as having internal linkage).

3 A name having namespace scope (3.3.6) has internal linkage if it is the name of
— ...
— a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously declared to have external linkage; or
— ...

j is explicitly declared const without being declared extern, hence it has internal linkage.

I believe clang is correct in this case because of §14.3.2/1 [temp.arg.nontype]

A template-argument for a non-type, non-template template-parameter shall be one of:
— ...
— a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage ...

j satisfies the requirement above and should be allowed as a non-type argument.

This is a bug, however is it known (and it is just not yet implemented, at least until gcc 4.9).

Here is the bug report

I expect gcc 5.0 to have that implemented, since 5.0 adds many new C++11 features.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top