C++11 provides a very handy operator decltype(e)
which allows one to query the resultant type of an expression which is not evaluated in runtime at all, only at the compilation time.
This, in conjunction with <type_traits>
, can be used to hand-write the template helpers for static_assert
's :
#include <type_traits>
template <typename T, typename = void>
struct is_equality_comparable : std::false_type {};
template <typename T>
struct is_equality_comparable<T,
typename std::enable_if<
std::is_convertible<decltype(std::declval<T&>() == std::declval<T&>())
, bool>{}>::type
> : std::true_type {};
template <typename T, typename = void>
struct is_less_than_comparable : std::false_type {};
template <typename T>
struct is_less_than_comparable<T,
typename std::enable_if<
std::is_convertible<decltype(std::declval<T&>() < std::declval<T&>())
, bool>{}>::type
> : std::true_type {};
That is, you can put any expression within decltype(e)
and check if it's e.g. convertible to boolean type, just like std::declval<T&>() < std::declval<T&>()
for less-than-comparability.
Now, whenever you want to add constraints to your template's parameter, just put a static_assert
within the class declaration.
Let's first define some classes that will be used for tests:
// sample equlity comparable type with **member** operator==
struct EqComparable
{
bool operator==(const EqComparable& other)
{
return i == other.i;
}
int i;
};
// sample less-than comparable type with **global** operator<
struct LessThanComparable
{
int i;
};
bool operator<(const LessThanComparable& lhs, const LessThanComparable& rhs)
{
return lhs.i < rhs.i;
}
// sample class which is not comparable in any way
struct NotComparableAtAll
{
};
Now let's apply constraints to the classes:
// your template classes with constraints:
template <typename T>
class MustBeEqComparable
{
static_assert(is_equality_comparable<T>::value,
"Type T is not equality comparable!");
};
template <typename T>
class MustBeLessThanComparable
{
static_assert(is_less_than_comparable<T>::value,
"Type T is not less than comparable!");
};
Now let's try to instantiate each:
MustBeEqComparable<EqComparable> a;
MustBeEqComparable<NotComparableAtAll> b; // issues an error
MustBeLessThanComparable<LessThanComparable> c;
MustBeLessThanComparable<NotComparableAtAll> d; // issues an error
DEMO