19
votes

While experimenting with the recent g++-5 compiler, I wrote below statement in a file:

template<T> T a;
template<> int a = 1;

Which results in:

warning: too many template headers for a (should be 0)

Also effectively, it doesn't really specialize a<int>. e.g.

template<typename T> T a;
template<> int a = 1;

int main ()  {
  std::cout << a<double> << "\n";  // prints 0; OK
  std::cout << a<int> << "\n";  // prints 0! why not 1?
}

What is the mystery about this syntax?

1
That is an awesomely misleading warning. I am surprised it was not an error. Was it the only diagnostic?Yakk - Adam Nevraumont
@Yakk, yes in g++-5 that is the only diagnostic. Not sure about clang, though.iammilind
Ah, I think I get the warning now! It is saying int a = 1; should have 0 template headers, where template< whatever > is one template header. Imagine if you deleted the template<class T> T a; before it -- the warning makes sense. Still shocking that it is a warning, not an error.Yakk - Adam Nevraumont
Coppied from here if you specialize [a variable template], then again it will result in multiple definition error. e.g. template<typename T> T a = 1; template<> int a = 0;, if you put this statement in a common header file then the ... statement will result in linker error.PaperBirdMaster

1 Answers

23
votes

Template arguments can only be omitted in explicit specialisation of function templates. You have a variable template, so you have to include the <int>:

template<> int a<int> = 1;

Quoting C++14 (n4140), 14.7.3/10 (emphasis mine):

A trailing template-argument can be left unspecified in the template-id naming an explicit function template specialization provided it can be deduced from the function argument type.

If you do not want to repeat the type, you can use auto:

template<> auto a<int> = 1;

[Live example] using Clang.

There's one thing to bear in mind with this: when using auto, the type of the specialised variable will be deduced from the initialiser, not from the template argument. And since a specialisation can have a different type than the primary template, the compiler will happily accept it even if they differ.