How to static_assert
a template type is EqualityComparable concept in C++11?
Asked
Active
Viewed 3,524 times
5

Andy Prowl
- 124,023
- 23
- 387
- 451

eonil
- 83,476
- 81
- 317
- 516
-
2Note that `static_assert` on template type arguments is sometimes a suboptimal idea. You'd often rather fail to match, which requires SFINAE, instead of fail to compile, which `static_assert` does. – Yakk - Adam Nevraumont May 06 '13 at 14:35
1 Answers
21
You could use the following type trait:
#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<
true,
decltype(std::declval<T&>() == std::declval<T&>(), (void)0)
>::type
> : std::true_type
{
};
Which you would test this way:
struct X { };
struct Y { };
bool operator == (X const&, X const&) { return true; }
int main()
{
static_assert(is_equality_comparable<int>::value, "!"); // Does not fire
static_assert(is_equality_comparable<X>::value, "!"); // Does not fire
static_assert(is_equality_comparable<Y>::value, "!"); // Fires!
}
Here is a live example.

Andy Prowl
- 124,023
- 23
- 387
- 451
-
1Minor correction: It won't work properly if T is not default constructible - make it `std::declval
()` instead of `T()`. – jrok May 06 '13 at 13:46 -
-
Strictly saying, it's not 100% EqualityComparable concept checking, because Commutativity and Transitivity reqs aren't checked. But as they cannot be checked in compile time, it's not a big deal, I guess. – Rost May 06 '13 at 14:01
-
Note that your check assumes `operator==` accepts rvalues - use `std::declval
()` for lvalues. – Xeo May 06 '13 at 14:02 -
I understand that it doesn't make much sense to have an equality operator accepting rvalues, but what is the point of using `std::declval
()` to force this restriction in the `is_equality_comparable` struct? Wouldn't it be better to have this generic code to work, regardless of how the user implemented his `operator==`? Am I missing something? – ChristopherC Dec 19 '14 at 07:53 -
1@ChristopherC: Whichever you choose (`declval
` or `declval – Andy Prowl Dec 19 '14 at 10:43`) there will always be a "non-idiomatic" signature that the trait is not going to recognize correctly. If I picked `declval `, types with an `operator ==` taking *modifiable* lvalue references would be recognized as non-equality-comparable. Granted, taking by modifiable lvalue reference makes little sense, but so does (or even less) taking by rvalue reference. -
Thanks @AndyProwl and @Xeo! This helped me out going into the right direction, towards answering [this question](http://stackoverflow.com/questions/27590890/how-to-check-at-compile-time-if-a-function-that-can-be-called-with-a-specific-se). – ChristopherC Dec 21 '14 at 16:09
-
declval
return a T && anyway (https://en.cppreference.com/w/cpp/utility/declval), so there is no difference between declval – Matthias May 19 '19 at 21:52and declval . -
2The std::enable_if is superfluous. The specialization can be simplified to template
struct is_equality_comparable< T, decltype(std::declval – Matthias May 19 '19 at 21:56() == std::declval (), (void)0)> : std::true_type {};