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 规范。
考虑这个 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 规范。