I want to overload (or specialize) a variadic function, such that the overload (or specialization) takes only arguments of a specific type. In C++20 I would write:
#include <type_traits>
#include <iostream>
// original version
void foo(auto const&...) { std::cout << "default\n"; }
// oveload/specialization takes only Bar instances
struct Bar {};
void foo(std::same_as<Bar> auto const&...){ std::cout << "Bar\n"; }
The code works as expected. The second version is chosen, if the arguments are all Bar
, the first otherwise. How would I create the second overload with C++17? Ideally, I wouldn't have to modify the more general version.
Here is a first failed attempt using std::enable_if
: https://godbolt.org/z/9vn39jTd4
You have "typo" in your attempt:
std::enable_if_t<(std::is_same_v<Bar, Ts> && ...), /* void */> = nullptr
is wrong.
std::enable_if_t<(std::is_same_v<Bar, Ts> && ...), std::nullptr_t> = nullptr
would fix the typo.
Unfortunately, it is insufficient. C++20 has subsumption to have more "specialized" overload.
With C++17, neither of
template <typename... Ts> void bar(Ts const& ...)
template <typename... Ts, std::enable_if_t<(std::is_same_v<Bar, Ts> && ...), std::nullptr_t> = nullptr> void bar(Ts const& ...)
is more specialized.
Fortunately, you can have:
template <typename... Ts,
std::enable_if_t<(std::is_same_v<Bar, Ts> && ...), std::nullptr_t> = nullptr
>
void bar(const Bar&, Ts const& ...){ std::cout << "Bar\n"; }
which is a better match.
Moreover, add overload for empty pack void bar()
if you consider no arguments as Bar
.
Note:
as {}
as no type, it can't be deduced, but as first argument of bar
IS a Bar
, bar({})
would works (whereas foo({})
won't).