The rules governing the exception specification for your two examples are covered in §8.4.2/2 [dcl.fct.def.default]
... If a function is explicitly defaulted on its first declaration,
— it is implicitly considered to be constexpr
if the implicit declaration would be,
— it is implicitly considered to have the same exception-specification as if it had been implicitly declared (15.4), and
— ...
Bar
's move constructor is noexcept(true)
because in §15.4/14 [except.spec]
An implicitly declared special member function (Clause 12) 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-id T
if and only if T
is allowed by the exception-specification of a function directly invoked by f
's implicit definition; f
shall allow all exceptions if any function it directly invokes allows all exceptions, and f
shall allow no exceptions
if every function it directly invokes allows no exceptions.
The rules in §8.4.2/2 do not apply to special member functions that have been explicitly defaulted after the initial declaration, except destructors, which are special cased in §12.4/3 to be noexcept(true)
unless you declare it noexcept(false)
or the destructors of one of the data members or base classes can throw.
Thus, unless you specify Foo(Foo&&)
to be noexcept(true)
, it is assumed to be noexcept(false)
.
The reason you needed to add the noexcept
specification to both the declaration and later explicit default declaration is found in §15.4
3 Two exception-specifications are compatible if:
— both are non-throwing (see below), regardless of their form,
— ...
4 If any declaration of a function has an exception-specification that is not a noexcept-specification allowing all exceptions, all declarations, including the definition and any explicit specialization, of that function shall have a compatible exception-specification. ...