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

时间:2015-04-16 23:18:39

标签: c++11 standards move exception-specification

考虑这个课程:

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

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

现在考虑一个C2相同的类,除了它的移动ctor在类定义之外是默认的:

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

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

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

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

我对C2的推理是否正确?

2 个答案:

答案 0 :(得分:6)

是的,您的解释是正确的,如果您公开声明,很容易证明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>{}, "");
}

答案 1 :(得分:1)

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

之间自由切换
C2::C2(C2&& rhs) {/* hand-written implementation here */}

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

并且该类的用户看不到。既然你没有默认 在第一个声明中,声明实际上是noexcept(false)和(无论好坏)保持这种方式,无论你的类中的子对象如何。违约的第一个宣言就是进一步“魔术” 也可以生成声明的noexcept规范。