The overloaded variadic version of a function is supposed to have the lowest priority, when the compiler chooses a template specialization. However, this is not the case when a function argument has to be upcasted to a base class first before it matches a template argument. See the example below.
class A {};
class B : public A {};
template<class... Args>
void foo(Args&&... argsPack) {
std::cout << "variadic function called" << std::endl;
}
void foo(A&) {
std::cout << "non-variadic function called" << std::endl;
}
int main() {
foo("Hello");
B b;
foo(b);
}
The output of this program results in
variadic function called
variadic function called
If I wanted the non-variadic function to be called, I would have to delete the variadic overloaded function entirely. Or alternatively I would have to write a third overloaded function that accepts instances of class B directly:
void foo(B&) {
std::cout << "non-variadic function called" << std::endl;
}
However, I want to avoid both solutions, because they are not elegant and error prone for my project. So is there a third solution for this?
You might constraint your template. I add extra overload to simplify the requirement:
void foo() // Simulate empty pack
{
std::cout << "variadic function called" << std::endl;
}
template <typename T, class... Args>
requires (!std::is_base_of_v<A, std::decay_t<T>> || sizeof...(Args) != 0)
void foo(T&& t, Args&&... argsPack) {
std::cout << "variadic function called" << std::endl;
}
void foo(A&) {
std::cout << "non-variadic function called" << std::endl;
}