6

The following code, which I derived reading this, compiles and behaves fine in gcc (link), but in Visual Studio gives an error.

Error C2910 'my_property<A<U>>': cannot be explicitly specialized

It works fine only if I remove the template <> line. I got the workaround here. The workaround version is ok also in g++.

#include <iostream>
#include <type_traits>

template <typename T>
struct A {
  T x;
};

template <typename T>
struct my_property {
  static const bool value = false;
};

template <> //Remove this and it will work in Visual Studio
template <typename U>
struct my_property<A<U>> {
  static const bool value = true;
};

int main() 
{
  std::cout << std::boolalpha;
  std::cout << my_property<int>::value << '\n'; //false
  std::cout << my_property<A<int>>::value << '\n'; //true
  std::cout << my_property<A<float>>::value << '\n'; //true
}

Which compiler is right?

Antonio
  • 19,451
  • 13
  • 99
  • 197
  • 3
    `template <>` -- that looks like nonsense. – Yakk - Adam Nevraumont Mar 14 '18 at 16:59
  • 1
    @Yakk Well, if you think about it, that's how you would introduce any explicit specialization. It actually looks pretty natural to me. – Antonio Mar 14 '18 at 17:03
  • @Yakk ...but is accepted by GCC and Clang w/ `-pedantic-errors`. The Clang warns about it having no effect though. – HolyBlackCat Mar 14 '18 at 17:07
  • 1
    also clang++ compile but with "warning: extraneous template parameter list in template specialization" (pointing the line `template <>`) – max66 Mar 14 '18 at 17:09
  • 1
    And, by the way, the error given by Visual Studio `cannot be explicitly specialized` looks totally misleading to me, because that's actually what we are able to achieve here. – Antonio Mar 14 '18 at 17:10
  • 3
    That is just a partial specialization. I've only ever seen two lines of `template <...>` used when you are referring to a template inside another template which is not the case here. – super Mar 14 '18 at 17:42
  • @super It's interesting how you can partially specialize a template which has only one template argument. It's counter-intuitive, but it makes sense the moment we see that one template argument as something that can be templated (somehow we "split" that one template argument). – Antonio Mar 14 '18 at 19:29

1 Answers1

3

If I read the standard correctly, template<> should not be used in this case.

Basically, you have to provide multiple template parameter lists for nested templates:

(see [temp.mem] §1)

A template can be declared within a class or class template; such a template is called a member template. A member template can be defined within or outside its class definition or class template definition. A member template of a class template that is defined outside of its class template definition shall be specified with the template-parameters of the class template followed by the template-parameters of the member template.

...but you don't need to provide an additional template parameter list for specializing a template with a template parameter:

(see [temp.class.spec] §2)

Each class template partial specialization is a distinct template...

(and then §4)

The template parameters are specified in the angle bracket enclosed list that immediately follows the keyword template. For partial specializations, the template argument list is explicitly written immediately following the class template name. For primary templates, this list is implicitly described by the template parameter list...

There's nothing to suggest that an additional template parameter list is required - a specialization is just a template, and as such it requires just a single parameter list.

shakurov
  • 2,358
  • 24
  • 27
  • I think the key here is that one can have partial specialization even if there is only one template argument (if you see that one template argument as something that can be "split" into a templetable class). A partial specialization can have more template parameters then the class being partially specialized!! – Antonio Mar 15 '18 at 20:29