4

I have a trait class that associates types to integer values.

struct traits
{
  private:
    template<int ID> struct type_impl {};
    template<> struct type_impl<1> { using type = int; };
    // ...

  public:
    template<int ID> using type = typename type_impl<ID>::type;

};

I am writing a template function which return type is provided by the traits class above and specialize it for various int values:

  template<int ID> traits::type<ID> function();
  template<> inline traits::type<1> function<1>() { return 42; };
  // ...

This compiles fine with VS2015 (see https://godbolt.org/z/LpZnni) but not with VS2017 that complains that:

error C2912: explicit specialization 'int function<1>(void)' is not a specialization of a function template

To my surprise, declaring a non template function like below compiles:

traits::type<1> other_function();

Making traits::type_impl public solves the compilation problem but I don't understand why. To me either both the specialization and the declaration of other_function should compile with traits::type_impl private or none.

Thank you for your help.

Further investigation following @rubenvb 's comment I understand that the code I posted is illegal, so I tried making partial specialization instead (which I believe is legal):

struct traits
{
  private:
    template<int ID,bool=true> struct type_impl {};
    template<bool B> struct type_impl<1,B> { using type = int; };
    // ...

  public:
    template<int ID> using type = typename type_impl<ID>::type;

};

template<int ID> traits::type<ID> function();
template<> inline traits::type<1> function<1>() { return 42; };

Now every compiler is happy but VS2017 that still wants traits::type_implpublic. I guess that's a Visual Studio bug.

1 Answers1

4

You have this code

struct traits
{
  private:
    template<int ID> struct type_impl {};
    template<> struct type_impl<1> { using type = int; }; // HERE

  public:
    template<int ID> using type = typename type_impl<ID>::type;
};

template<int ID> traits::type<ID> function();
template<> inline traits::type<1> function<1>() { return 42; };

The line marked with //HERE contains an in-class template specialization. This is illegal in C++.

The thing we learn from this is that Visual Studio has terrible error messages when templates are involved. In case the issue isn't immediately clear, see what another compiler says. A different compiler often points to different issues or talks about them differently, which may at the very least provide a good hint on where the actual problem originates.

The Intel compiler shows this:

error: explicit specialization is not allowed in the current scope
  template<> struct type_impl<1> { using type = int; };
  ^

GCC shows this:

error: explicit specialization in non-namespace scope 'struct traits'
    5 |     template<> struct type_impl<1> { using type = int; };
      |              ^

Clang doesn't seem to mind for some reason. This seems to be a bug.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • I don't understand what was missing from my question that you found with the godbolt link? – Yohann Bénédic May 07 '19 at 12:01
  • Anyway that perfectly answers my question, thank you very much! – Yohann Bénédic May 07 '19 at 12:02
  • @Yohann Sorry, my bad. I had scrolled down a bit and only saw what I wanted to see. And you're welcome! – rubenvb May 07 '19 at 12:47
  • 1
    _"The line marked with `//HERE` contains an in-class **function** template specialization"_ Sorry, which function template exactly is specialized in that line? – Max Langhof May 07 '19 at 13:49
  • I have just noticed that you mentioned 'function specialization' as illegal inside class scope in you answer but it is a class specialization that I am doing. I believe full specialization of a class template is also illegal inside a class, but not partial specialization. Therefore I added a dummy template parameter and that made every compiler I tried happy, except VS that still wants the whole thing to be public. – Yohann Bénédic May 07 '19 at 14:27
  • Right, it's not a function template specialization, but a struct template specialization. Both are errors though. – rubenvb May 08 '19 at 08:30