Mr.C64 Mr.C64 - 1 month ago 14
C++ Question

Defining a custom predicate as a combination of std::is_same

I have a function template and I'd like to restrict the set of types for which it can be instantiated.

I wrote something like this:

template <typename T>
void DoSomething( /* ... Some parameters involving T ... */)
{
// Check at compile-time that T is allowed
static_assert(
std::is_same<T, int>::value
|| std::is_same<T, float>::value
|| std::is_same<T, double>::value
...
|| std::is_same<T, /* other type */>::value,
"Type not allowed");
}


I have to repeat the same check for other function templates.

An obvious solution would be copy-and-paste'ing the above
static_assert
check, but that would be bad for code maintainability.

A better solution might be to wrap the
static_assert
check in an ad hoc helper function, and call it in each function templates in which I need the type check.

But what I think would be more elegant is defining a custom combination of
std::is_same
calls, that I could use like this:

static_assert(IsTypeAllowed<T>::value, "Type not allowed");


How can I define my custom
IsTypeAllowed<T>
as a combination of
std::is_same
calls
||
'ed together?

Answer

In C++1z you can roll your own trait with std::disjunction:

template<typename T, typename... Others>
struct is_any : std::disjunction<std::is_same<T, Others>...>
{
};

Then it's as simple as

static_assert(!is_any<int,char,bool>::value);
//static_assert(!is_any<int,char,bool,int>::value); //error   

demo

You can map it further to get the exact interface you asked for:

template<typename T>
using IsTypeAllowed = std::bool_constant<!is_any<T, char, bool, int>>;

If you need this in C++14, you needn't look father than the possible implementation provided by cppreference:

template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...> 
    : std::conditional_t<B1::value != false, B1, disjunction<Bn...>>  { };