class 之外定义的默认移动操作的异常规范是什么?

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

考虑这个 class:

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

因为 C1 的移动构造函数在其第一个声明中明确默认,标准的 8.4.2 告诉我们它具有相同的异常规范 (ES),就好像该函数已被隐式声明一样。然后我们可以用15.4/14和12.8/15得出它的ES是noexcept(true).

现在考虑一个相同的 class C2,除了它的移动构造函数默认在 class 定义之外:

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

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

C2 的移动指令的 ES 是什么?因为它在第一次声明时没有违约,所以 8.4.2/2 不适用。因为它没有明确的 ES,所以 8.4.2/3 不适用。因为它没有隐式声明,所以 15.4/14 不适用。据我所知,这意味着 15.4/12 适用,并且它表示默认函数 ES 是 noexcept(false).

如果我是对的,那意味着 C1 中的移动构造函数是 noexcept(true),但 C2 中概念上相同的移动构造函数是 noexcept(false)

我对 C2 的推理是否正确?

是的,你的解释是正确的,如果你声明public,很容易证明clang和gcc都同意你的推理:

#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>{}, "");
}

解释正确,是的。在第一个声明之后默认意味着生成函数体而不对声明执行任何魔法。如果定义在不同的翻译单元,可以自由切换

C2::C2(C2&& rhs) {/* hand-written implementation here */}

C2::C2(C2&& rhs) = default;

class 的用户不可见。因为你没有违约 在第一个声明中,声明实际上是 noexcept(false) 并且(无论好坏)保持这种状态,而不管 class 中的子对象。在第一个声明中违约会进一步 "magic" 还可以生成声明的 noexcept 规范。