Reputation: 14987
I've being testing with GCC 5.2 and clang 3.6, both in C++14 mode, and they give the same output.
For the following code
#include <iostream>
#include <type_traits>
struct S {
// S& operator= (S&&) noexcept { return *this; }
};
int main() {
std::cout << std::is_nothrow_move_constructible<S>::value
<< std::is_nothrow_move_assignable<S>::value;
}
the result 11
is obtained. But if uncomment the move assignment operator, the output becomes 01
. How could an explicit noexcept
specification on the move assignment operator possibly affect that of the move constructor?
Upvotes: 3
Views: 483
Reputation: 118021
By defining the move assignment operator, you disabled the move constructor due to the rule of 5. The class isn't is_nothrow_move_constructible
because it isn't move constructable at all, that constructor is no longer available unless you define it.
§12.8 Copying and moving class objects
If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
—X
does not have a user-declared copy constructor,
—X
does not have a user-declared copy assignment operator,
—X
does not have a user-declared move assignment operator,
—X
does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
In the case where you had no user-defined move constructor, both were implicitly defined and followed the below specification.
§15.4 Exception specifications
An implicitly declared special member function shall have an exception-specification. If
f
is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idT
if and only ifT
is allowed by the exception-specification of a function directly invoked byf
’s implicit definition;f
shall allow all exceptions if any function it directly invokes allows all exceptions, andf
shall allow no exceptions if every function it directly invokes allows no exceptions.
Upvotes: 7
Reputation: 37924
By declaring a move assignment, you've lost your implicit move constructor.
See the full chart below.
Upvotes: 5
Reputation: 72483
12.8/9:
If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
X
does not have a user-declared copy constructor,
X
does not have a user-declared copy assignment operator,
X
does not have a user-declared move assignment operator, and
X
does not have a user-declared destructor.
By declaring a move assignment operator, you prevent the class from having any move constructor at all.
Upvotes: 2
Reputation: 3977
The move constructor is simply not generated in this case - it has nothing to do with noexcept
.
From cppreference:
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
- there are no user-declared copy constructors
- there are no user-declared copy assignment operators
- there are no user-declared move assignment operators
- there are no user-declared destructors (until C++14)
the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
Upvotes: 2
Reputation: 11
By defining the move operator, you've suppressed the implicit move constructor. That's why std::is_nothrow_move_constructible
fails. Provide it to get the desired output:
struct S {
S(S&&) noexcept {}
S& operator= (S&&) noexcept { return *this; }
};
Upvotes: 1