To limit a template parameter pack to a certain type, this can be done in the following way:
std::enable_if_t<std::conjunction_v<std::is_same<int32_t, Ts>...>>
send(bool condition, Ts...);
I would actually allow int32_t and std::string and any order.
How can this be expressed?
I had a workaround using a variant, but this does not look so nice to me:
using allowed_types = std::variant<int32_t, std::string>;
template<typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_assignable<allowed_types, Ts>...>>
send(bool condition, Ts...);
And this does not compile:
std::enable_if_t<std::conjunction_v<std::is_same<int32_t, Ts> || std::is_same<std::string, Ts>...>> // <- does not compile!
send(bool condition, Ts...);
You are using std::conjunction
as a replacement for &&
on the std::bool_constant
level correctly, but then you should in the same way replace ||
with std::disjunction
:
std::enable_if_t<std::conjunction_v<std::disjunction<std::is_same<int32_t, Ts>, std::is_same<std::string, Ts>>...>>
or with C++17 you can use fold expressions on the level of bool
values instead:
std::enable_if_t<((std::is_same_v<int32_t, Ts> || std::is_same_v<std::string, Ts>) && ...)>>
(Outer parentheses are required by the fold expression syntax.)
Of course with C++20 this can be done much nicer with the help of concepts:
template<typename T>
concept Int32OrString = std::same_as<T, int32_t> || std::same_as<T, std::string>;
void send(bool condition, Int32OrString auto...);
or even
template<typename T, typename... Ts>
concept AnyOf = (std::same_as<T, Ts> || ...);
void send(bool condition, AnyOf<int32_t, std::string> auto...);