Reputation: 3859
I need enable std::string and int, but using a parameter pack.
template <typename... ParamType, typename = typename std::enable_if<std::is_same<ParamType..., std::string>::value || std::is_same<ParamType..., int>::value>::type>
static inline void Log(const ParamType & ... args)
{
}
but i have errors when call
Log("hello"s, "world"s); //syntax ERROR
Desired result
Log(4,3,"Hello"s); //OK
Log("Hello"s); //OK
Log(5); //OK
Upvotes: 1
Views: 74
Reputation: 48457
In c++17 using fold-expressions:
#include <type_traits>
template <typename... ParamType>
static inline auto Log(const ParamType&... args)
-> std::enable_if_t<((std::is_same_v<ParamType, std::string>
|| std::is_same_v<ParamType, int>) && ...)>
{
}
However, if there's no alternative overload of Log
, that could be used for parameters that do not satisfy the condition, consider using static_assert
instead to provide an informative error message:
template <typename... ParamType>
static inline void Log(const ParamType&... args)
{
static_assert(((std::is_same_v<ParamType, std::string>
|| std::is_same_v<ParamType, int>) && ...)
, "Only ints and strings");
}
In c++20 using concepts:
#include <type_traits>
template <typename T>
concept LogParam = std::is_same_v<T, std::string> || std::is_same_v<T, int>;
static inline void Log(const LogParam auto&... args)
{
}
Upvotes: 0
Reputation: 118340
This solution uses a few C++17-ism (std::void_t
). There are various implementations of them for earlier C++ standards floating everywhere, if needed:
template <typename ... ParamType,
typename = std::void_t<std::enable_if_t
<std::is_same_v<ParamType, std::string> ||
std::is_same_v<ParamType, int>>...>>
static inline void Log(const ParamType & ... args)
{
}
Upvotes: 2
Reputation: 40826
You want (is_string_or_int(param_0)) && (is_string_or_int(param_1)) && (is_string_or_int(param_2)) && ...
. This can be written with the fold expression:
typename std::enable_if<
(true && ... && (
std::is_same<ParamType, std::string>::value ||
std::is_same<ParamType, int>::value
))
>::type
This only works with C++17 and above. For a C++11 friendly solution, you can go for struct specializations to iterate over the types:
// true iff Testing is any of Required...
template<typename Testing, typename... Required>
struct one_match : std::false_type {};
template<typename Testing, typename First, typename... Rest>
struct one_match<Testing, First, Rest...> : std::bool_constant<std::is_same<Testing, First>::value || one_match<Testing, Rest...>::value> {};
// true iff all of TestingTypes... are in the tuple RequiredTypesTuple
template<typename RequiredTypesTuple, typename... TestingTypes>
struct all_match;
template<typename... RequiredTypes>
struct all_match<std::tuple<RequiredTypes...>> : std::true_type {};
template<typename... RequiredTypes, typename First, typename... Rest>
struct all_match<std::tuple<RequiredTypes...>, First, Rest...> : std::bool_constant<one_match<First, RequiredTypes...>::value && all_match<std::tuple<RequiredTypes...>, Rest...>::value> {};
template <typename... ParamType, typename enabler =
typename std::enable_if<
all_match<std::tuple<std::string, int>, ParamType...>::value
>::type>
static inline void Log(const ParamType & ... args)
{
}
Upvotes: 0