lundi 30 janvier 2017

Impossible implicit move operations?

As far as I understand [class.copy.ctor] and [class.copy.assign], struct A in the following code should not be move-constructible nor move-assignable:

#include <type_traits>


struct X {
  X() noexcept; // user-declared default constructor
  ~X() noexcept; // Force X not to be trivially copyable
  X(X &&) = delete; // Explicitly deleted move constructor
  X(X const &) = delete; // Explicitly deleted copy constructor
  X & operator=(X &&) = delete; // Explicitly deleted move assignment operator
  X & operator=(X const &) = delete; // Explicitly deleted copy assignment op.
};
static_assert(!std::is_copy_constructible<X>::value, "");
static_assert(!std::is_copy_assignable<X>::value, "");
static_assert(!std::is_move_assignable<X>::value, "");
static_assert(!std::is_move_constructible<X>::value, "");
static_assert(!std::is_trivially_copyable<X>::value, "");
static_assert(!std::is_trivially_copy_assignable<X>::value, "");
static_assert(!std::is_trivially_copy_constructible<X>::value, "");
static_assert(!std::is_trivially_move_assignable<X>::value, "");
static_assert(!std::is_trivially_move_constructible<X>::value, "");


struct A {
  A() noexcept; // user-declared default constructor
  A(A const &) noexcept; // user-declared copy constructor
  A & operator=(A const &) noexcept; // user-declared copy assignment operator
  X x;
};
static_assert(std::is_copy_constructible<A>::value, "");
static_assert(std::is_copy_assignable<A>::value, "");
static_assert(!std::is_move_assignable<A>::value, "");        // FAILS?!
static_assert(!std::is_move_constructible<A>::value, "");     // FAILS?!
static_assert(!std::is_trivially_copyable<A>::value, "");
static_assert(!std::is_trivially_copy_assignable<A>::value, "");
static_assert(!std::is_trivially_copy_constructible<A>::value, "");
static_assert(!std::is_trivially_move_assignable<A>::value, "");
static_assert(!std::is_trivially_move_constructible<A>::value, "");

However, two of the static assertions fail with both GCC and Clang, which mean that for some reason A is move-assignable and move-constructible.

In my reasoning this shouldn't be, because struct A:

  • does not explicitly declare a move constructor
  • does not explicitly declare a move assignment operator
  • has a user-declared copy constructor
  • has a user-declared copy assignment operator.
  • has a field x of type X which is can not be direct-initialized with any other A::x, because all constructors of X which would participate in overload resolution for this are explicitly deleted.

Is this a compiler bug or am I misunderstanding something?

Aucun commentaire:

Enregistrer un commentaire