Search code examples
c++11standardsmoveexception-specification

What is the exception specification for a defaulted move operation defined outside the class?


Consider this class:

class C1 {
  C1(C1&&) = default;        // declare and define move ctor
};

Because C1's move ctor is explicitly defaulted on its first declaration, 8.4.2 of the Standard tells us it has the same exception specification (ES) as if the function had been implicitly declared. We can then use 15.4/14 and 12.8/15 to conclude that its ES is noexcept(true).

Now consider a class C2 that is the same, except its move ctor is defaulted outside the class definition:

class C2 {
  C2(C2&&);                 // declare move ctor
}; 

C2::C2(C2&&) = default;     // define move ctor

What is the ES for C2's move ctor? Because it's not defaulted on its first declaration, 8.4.2/2 doesn't apply. Because it doesn't have an explicit ES, 8.4.2/3 doesn't apply. Because it's not implicitly declared, 15.4/14 doesn't apply. From what I can tell, that means that 15.4/12 applies, and it says that the default function ES is noexcept(false).

If I'm right, that means that the move ctor in C1 is noexcept(true), but the conceptually identical move ctor in C2 is noexcept(false).

Is my reasoning about C2 correct?


Solution

  • Yes, your interpretation is correct, and if you make your declarations public, it is easy to show that both clang and gcc agree with your reasoning:

    #include <type_traits>
    
    class C1
    {
    public:
      C1(C1&&) = default;        // declare and define move ctor
    };
    
    class C2 {
    public:
      C2(C2&&);                 // declare move ctor
    }; 
    
    C2::C2(C2&&) = default;     // define move ctor
    
    int
    main()
    {
        static_assert(std::is_nothrow_move_constructible<C1>{}, "");
        static_assert(!std::is_nothrow_move_constructible<C2>{}, "");
    }