Related but much more arcane than C++11 static assert for equality comparable type? —
JF Bastien's paper N4130 "Pad Thy Atomics!" got me thinking that if we're going to use atomic<T>::compare_exchange_weak()
where T
is a class or struct type, such as
struct Count {
int strong_count;
int weak_count;
};
then we really want to static-assert two things:
First, that T
is actually lock-free atomic:
template<class T>
static constexpr bool is_lockfree_atomic_v =
std::atomic<T>::is_always_lock_free;
And second, that compare_exchange_weak
will do what we want. Recall (or from N4130) that compare_exchange_weak
is defined in terms of memcmp
and memcpy
. So we need to check that those functions will do the right thing as far as T
is concerned:
template<class T>
static constexpr bool is_cmpxchgable_v =
std::is_trivially_copyable_v<T> &&
is_trivially_equality_comparable_v<T>;
is_trivially_copyable_v
is provided by the STL. But we don't have an is_trivially_equality_comparable_v
yet — and my understanding, sadly, is that P0515 Consistent Comparison does not propose to provide one. (P0515 is the feature that will allow the compiler to detect that the equality operator is literally "trivial" — that it is not user-provided and that it is explicitly defaulted under such-and-such conditions. However, it does not introduce any new concept such as "trivially comparable" into the core language.)
My best stab at a "trivially comparable" trait looks like this:
template<class T, class U>
static constexpr bool is_equality_comparable_with_v =
requires(std::declval<T>() == std::declval<U>());
template<class T>
static constexpr bool is_equality_comparable_v =
is_equality_comparable_with_v<T, U>;
template<class T>
static constexpr bool is_trivially_equality_comparable_v =
is_equality_comparable_v<T> &&
std::has_unique_object_representations_v<T>;
However, this definition relies on std:: has_unique_object_representations_v
, [EDIT: which has undefined behavior whose value is unrelated to the behavior of operator==
] when T
is not a scalar type. And I strongly suspect that in practice has_unique_object_representations_v
will return garbage for struct types such as my original Count
type.
struct Yes { int a; int b; };
struct No { short a; int b; };
using Yes2 = std::tuple<int, int>;
struct No2 { int a; int b; bool operator==(const No2&) { return true; }};
- Clang/libc++ does not implement
has_unique_object_representations
yet. - MSVC does not implement
has_unique_object_representations
yet, AFAIK. - GCC/libstdc++ says that
has_unique_object_representations_v<Yes>
, and even reports correctly thatnot has_unique_object_representations_v<No>
, but reports incorrectly thatnot has_unique_object_representations_v<Yes2>
and thathas_unique_object_representations_v<No2>
.
So my questions are, (1) is there a better way to test for "trivial comparability"? and (2) is there any movement in the direction of a proposal for is_trivially_equality_comparable
(and is_trivially_less_than_comparable
and so on), if P0515 gets into the standard for C++20? and (3) should there be?