Question

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?
Was it helpful?

Solution

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
  • [...]

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top