19

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?

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 4
    That is an awesomely misleading warning. I am surprised it was not an error. Was it the only diagnostic? – Yakk - Adam Nevraumont May 05 '15 at 11:32
  • @Yakk, yes in g++-5 that is the only diagnostic. Not sure about clang, though. – iammilind May 05 '15 at 11:46
  • 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 T a;` before it -- the warning makes sense. Still shocking that it is a warning, not an error. – Yakk - Adam Nevraumont May 05 '15 at 13:10
  • Coppied from [here](http://stackoverflow.com/questions/29367350/template-instance-in-different-translation-units/29367507?noredirect=1#comment48217223_29367507) *if you specialize [a variable template], then again it will result in multiple definition error. e.g. `template 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 May 05 '15 at 14:05

1 Answers1

23

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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Interesting, the in between `int` seems redundant to write :-). Anyhow, `template<> auto a = 1;` also works! – iammilind May 05 '15 at 11:33
  • 2
    Be careful with `auto` here. If you're expecting the variable to have the same type as the template argument (which won't necessarily match the initialiser), then you might have a surprise. – Mike Seymour May 05 '15 at 11:50
  • @MikeSeymour True indeed, I will add a caveat to the answer. – Angew is no longer proud of SO May 05 '15 at 11:56
  • Note that you might _intentionally_ want your variable template to have a different type than the type of the template argument. Usages like `template bool predicate = false; template<> bool predicate = true;` were probably more what the committee had in mind. – zwol May 05 '15 at 15:09
  • @zwol I know it's possible to want a different type for the specialisation. It's because it's not what the OP wants here that I added the caveat. – Angew is no longer proud of SO May 05 '15 at 20:31