Consider the following move-only type:
struct MoveOnly
{
MoveOnly() = default;
~MoveOnly() = default;
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) noexcept = default;
MoveOnly& operator=(MoveOnly&&) noexcept = default;
};
Both GCC and Clang agree on:
static_assert(not std::is_trivially_copy_constructible_v<MoveOnly>);
static_assert(not std::is_copy_constructible_v<MoveOnly>);
static_assert( std::is_trivially_copyable_v<MoveOnly>);
Now consider this wrapper type that propagates trivial copy construcibility:
template <typename T>
struct Wrapper
{
Wrapper(const Wrapper&)
requires(!std::is_trivially_copy_constructible_v<T> && std::is_copy_constructible_v<T>)
{
}
Wrapper(const Wrapper&)
requires(std::is_trivially_copy_constructible_v<T>) = default;
};
Both GCC and Clang agree on:
static_assert(not std::is_trivially_copy_constructible_v<Wrapper<MoveOnly>>);
static_assert(not std::is_copy_constructible_v<Wrapper<MoveOnly>>);
However, GCC believes the following is true, while Clang believes it’s false:
static_assert( std::is_trivially_copyable_v<Wrapper<MoveOnly>>);
// passes on GCC, fails on Clang
What compiler is correct here and why?
live example on Compiler Explorer
1