Search code examples
c++templatesspecializationparameter-pack

Q: Template specialization with parameter pack


I'll get right to the question.

We have template specialization:


class TestClass
{
public:
   template<typename T>
   static T fn(const T& a);
}

// OK
template<typename T>
T TestClass::fn(const T& a)
{
   // ... magic for any type here ...
}


// OK
template<>
int TestClass::fn(const int& a)
{
   // ... magic for int type here ...
}

All okay. But what if I want to add a parameter pack to the function?

class TestClass
{
public:
   template<typename T, typename... Args>
   static T fn(const T& a, Args&& ...b);
}

// OK
template<typename T, typename... Args>
T TestClass::fn(const T& a, Args&& ...b)
{
   // ... magic for any type here ...
}

// Error
template<typename... Args>
int TestClass::fn(const int& a, Args&& ...b)
{
   // ... magic for int type here ...
}

Visual Studio gives error E0147. How can I do this without adding a new function to the class?

Thanks in advance for your help!

Have a nice day!


Solution

  • In your first example

    template<>
    int TestClass::fn(const int& a)
    { /* ... */ }
    

    you have a full specialization, that is permitted for C++ template functions/methods

    But, given the declaration

    template<typename T, typename... Args>
    static T fn(const T& a, Args&& ...b);
    

    your second example

    template<typename... Args>
    int TestClass::fn(const int& a, Args&& ...b)
    { /* ... */ }
    

    become a partial specialization, that isn't permitted for C++ functions/methods.

    But you can use overloading, avoiding specialization at all, adding a declaration for a different template method with the same name.

    I mean

    class TestClass
    {
    public:
       template <typename T, typename ... Args>
       static T fn (T const & a, Args && ... b);
    
       template <typename ... Args>
       static T fn (int const & a, Args && ... b);
    };
    
    template <typename T, typename ... Args>
    T TestClass::fn (T const & a, Args && ... b)
     { /* ... */ }
    
    template <typename ... Args>
    int TestClass::fn (int const & a, Args && ... b)
     { /* ... */ }