0

I'm struggling with coding explicit specialization of variadic template of member function in a pretty way. The problem is that standard forbids explicit specializations in non-namespace scopes as explained here. MSVC allows such thing, but GCC (and probably some other more standard-respecting compilers) doesn't.
Reproduction of the problem (let's say it's just printing for simplicity)

struct A
{
   template<typename ...Args>
   A(Args... args) { print(int(args)...); }

   template<typename ...Rest>
   void print(int first, Rest... rest) const
   {
       std::cout << first;
       print(int(rest)...);
   }
   template<>
   void print(int first) const { std::cout << first; }
};

int main()
{
   A(1, 3, 2, 5, 7, 4);
}

In provided link there's much simpler situation mainly because of just one template parameter and lack of 'recursion'. I can't find a way to get this working and in not eyes-bleeding manner.
Besides provided reproduction I also got exactly the same problem, but with constructor which makes this even more complex...

Criss
  • 581
  • 5
  • 17

1 Answers1

1

Write a normal overload?

void print(int first) const { std::cout << first; }

Demo


Barring that, assuming your example is actually a bit more complicated, you may want to look into tagged dispatch:

struct A
{
    template<class... Args>
    struct A_tag{};

    template<typename ...Args>
    A(Args... args) { print(A_tag<Args...>{}, int(args)...); }

    template<typename ...Rest>
    void print(A_tag<int, Rest...>, int first, Rest... rest) const
    {
        std::cout << first;
        print(A_tag<Rest...>{}, int(rest)...);
    }

    void print(A_tag<int>, int first) const { std::cout << first; }
};

Demo 2

The idea behind the tagged dispatch approach is still to take advantage of overloading, but it does so having the overloads accept a tag struct that is specialized on a certain type.

Tagged functions can be hidden as private, and you can expose pretty looking non-tagged functions.

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • Uhh.. It was that simple... I still had in mind that `template void f(T){} void f(int){}` is an UB and for some reason I also avoided just overloading here. Ofc my concern here is just irrelevant, but I decided so without even thinking :D Also thank you for the tagged dispatch example - something new to know. Anyway just an overload was just fine in both of my problematic situations. – Criss Aug 10 '17 at 00:20