1

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.

2
  • Since function template doesn't support partial specialization, you can overload Func and constrain it using requires as shown here. See working demo Commented Apr 14, 2024 at 5:18
  • Just write if constexpr instead of specializing. Commented Apr 14, 2024 at 5:25

2 Answers 2

2

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";
    }

    
}  
Sign up to request clarification or add additional context in comments.

3 Comments

I was thinking about this too, but then you would need to strip of the first argument of Args in the first if to be able to use the remainder args (or SomeClass will always be the first argument type)
@PepijnKramer Yup, but that seems like a follow up question that should be asked separately by OP assuming they want that.
Quite likely ;)
2

It is possible to do this, but you will have to add an extra first argument that represents the type of class you want to specialize on. And then you can use the type deduction system of C++, it will match the function with the most specific match (normal function overloading first).

#include <iostream>
#include <utility>
#include <type_traits>

struct A{};
struct SomeClass{};

struct MyClass
{

    template<typename T, typename... Args>
    void Func(const T&, std::size_t id, Args&&... args) // use rvalue references for args (avoids copying of temporaries)
    {
        std::cout << "id = " << id << ", args : ";

        ((std::cout << std::forward<Args>(args) << " "), ...); // C++17 fold expression use std::forward to keep "rvalue" reference(ness)
        std::cout << "\n";
    }

    template<typename... Args>
    void Func(const SomeClass&, std::size_t id, Args&&... args) // use rvalue references for args (avoids copying of temporaries)
    {
        std::cout << "SomeClass : ";
        std::cout << "id = " << id << ", args : ";
        ((std::cout << std::forward<Args>(args) << " "), ...); // C++17 fold expression
        std::cout << "\n";
    }
};



int main()
{
    A a{};
    SomeClass s{};
    MyClass c;

    c.Func(a,1ul,1,2);
    c.Func(s,1ul,1,2,3);
}

2 Comments

@user12002570 Ehm yes fixed that.
std::type_identity might be used to pass (deducible) types, instead of dummy instance (which are not always possible to have anyway, as void).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.