1. Revision history
Since [P1286R1]:
- 
     Addressed CWG wording review comments. 
- 
     Addressed LWG wording review comments by removing library wording; the fixes will be left for [LWG2334]. 
Since [P1286R0]:
- 
     Remove discussion of options; EWG has selected their desired alternative. 
- 
     Approved unanimously by EWG. 
2. Background
See lists.isocpp.org/core/2018/01/3741.php for more information.
2.1. CWG 1778: exception-specification in explicitly-defaulted functions
Prior to [CWG1778], we required that:
An explicitly-defaulted function [...] may have an explicit exception-specification only if it is compatible with the exception-specification on the implicit declaration.
It was observed in [LWG2165] that this creates problems for 
template < typename T > struct atomic { atomic () noexcept = default ; 
... which (it was believed) resulted in 
2.2. Potential fixes
[LWG2165] lists the following as potential fixes:
- 
     Add nothrow default constructible to requirements for template argument of the generic atomic < T > 
- 
     Remove atomic < T >:: atomic () T 
- 
     Remove noexcept atomic < T >:: atomic () noexcept 
- 
     Do not default atomic < T >:: atomic () atomic < T > 
- 
     A core change to allow the mismatched exception specification if the default constructor isn’t used (see c++std-core-21990) 
2.3. Language change
CWG chose to resolve the issue by changing the rule to:
If a function that is explicitly defaulted has an explicit exception-specification that is not compatible with the exception-specification on the implicit declaration, then
if the function is explicitly defaulted on its first declaration, it is defined as deleted;
otherwise, the program is ill-formed.
That is: implicitly delete the default constructor if the specified exception specification doesn’t match the implicit one.
3. Problem
3.1. Existing approach is bad for compilers
Exception specifications are a complete-class context: they are a place where all members of the class and its enclosing classes can be used, just like member function bodies, default arguments, and default member initializers. This means we cannot in general determine the implicit exception specification of a member function until we reach the end of the outermost lexically-enclosing class. However, we need to know which special member functions a class has, and whether or not they are deleted, immediately after the class becomes complete, which (for a nested class) may be earlier.
Example:
struct X { X (); }; struct A { struct B { B () noexcept ( A :: value ) = default ; X x ; }; decltype ( B ()) b ; static constexpr bool value = true; }; A :: B b ; 
Here, we do not parse the exception specification for 
Note that we cannot possibly tell whether the call to 
3.2. Existing approach is unnecessary for std :: atomic < T > 
   The existing core rule arose because of concern over a case such as
struct Foo { Foo () : n ( 0 ) {} // happens to not be noexcept int n ; }; std :: atomic < Foo > f ; 
... being ill-formed. But it is not: the intent of
the 
If the default constructor of 
3.3. Existing approach prevents a useful feature
Consider the following pattern, which we found several instances of in our codebase when we tightened up the compiler to reject a mismatched exception specification on a defaulted function:
struct X { std :: map < ... > m ; // ... other members public : // I want a defaulted move constructor, and vector<X> needs to be // efficient, so please call std::terminate if moving the map throws // rather than slowing my code down with unnecessary copies X ( X && ) noexcept = default ; }; 
Users wanting this feature are forced to write out their own
special members, which is an error-prone operation that 
4. Approach
If the user explicitly specifies an exception specification on a defaulted function, that’s the exception specification. Don’t delete the function, don’t reject the program, just accept it.
5. Wording
Change in [dcl.fct.def.default]/2:
The type
of an explicitly defaulted functionT1 is allowed to differ from the typeF it would have had if it were implicitly declared, as follows:T2 
andT1 may have differing ref-qualifiers; andT2 
andT1 may have differing exception specifications; andT2 
if
has a parameter of typeT2 , the corresponding parameter ofconst C & may be of typeT1 .C & [...]
Change in [dcl.fct.def.default]/4:
//~ S () noexcept ( false) = default ; deleted: exception specification does not matchOK, despite mismatched exception specification
Add the following to the example in [dcl.fct.def.default]/4:
struct T { T (); T ( T && ) noexcept ( false); }; struct U { T t ; U (); U ( U && ) noexcept = default ; }; U u1 ; U u2 = static_cast < U &&> ( u1 ); // OK, calls std::terminate if T::T(T&&) throws 
Do not make any changes to [atomics.types].