c++templatesvariadic-templatestemplate-specializationentity-component-system

Template function with variadic arguments speciaization


Is it possible somehow to do template function specialization like this:

template<typename T, typename... Args>
void Func(size_t id, Args... args) { std::cout << "1\n" }

template<>
void Func<SomeClass>(size_t id, Args... args) { std::cout << "2\n" }

So I want to leave variadic Args, but specify T = SomeClass:

Func<A>(1, 2, 3); // 1
Func<SomeClass>(1, 2); // 2

I know that I can use "little hack" - wrap func into a class and make partial specialization for it, but in my case this doesn't work, because Func() is actually some class method and it initializes some members of this class. So hack-class should has pointer to it and be friend to it (because members is private) which is also problem.

And also this hack looks a little scary and unreadable.


Solution

  • Is it possible somehow to do template function specialization like this

    We can't partially specialize function templates. But there are ways to have the same effect as you want.

    Method 1

    With you can constrain Func using requires as shown below.

    template<typename T, typename... Args>
    void Func(std::size_t id, Args... args) 
    { 
        std::cout << "1\n";
    }  
    //overload for SomeClass
    template<typename T, typename... Args>
    void Func(std::size_t id, Args... args) requires(std::is_same_v<T, SomeClass>)
    { 
        std::cout << "2\n";
    }
    int main()
    {
        Func<A>(1, 2, 3);    // 1
        Func<SomeClass>(1, 2);  // 2
     
    }
    

    Working demo

    Method 2

    Another alternative is to use constexpr if as shown below:

    template<typename T, typename... Args>
    void Func(std::size_t id, Args... args) 
    { 
        if constexpr(std::is_same_v<T, SomeClass>)
        {
               std::cout << "2\n";
        }
        else 
        {
           std::cout << "1\n";
        }
    
        
    }