std :: is_nothrow_move_constructible是否需要一个noexcept析构函数?

Sim*_*mon 6 c++ type-traits language-lawyer c++11

以下代码无法使用Visual Studio 2017(15.5),gcc 6.4.0和clang 4.0.1进行编译,即静态断言失败:

struct Type
{
  Type(Type&&) noexcept {}

  ~Type() noexcept(false) {}
};

static_assert(std::is_nothrow_move_constructible<Type>::value, "Type should be nothrow-move-constructible");
static_assert(std::is_nothrow_constructible<Type, Type&&>::value, "Type should be nothrow-constructible from Type&&");
Run Code Online (Sandbox Code Playgroud)

这是正确的C++标准吗?是否std::is_nothrow_move_constructible需要noexcept析构函数?为什么?

如果我使用这样的:

Type a;
Type b(std::move(a));  
Run Code Online (Sandbox Code Playgroud)

a在第二个语句中没有调用析构函数.

Sha*_*our 2

我们可以看到std::is_nothrow_move_constructible是根据is_\xc2\xadnothrow_\xc2\xadconstructible_\xc2\xadv定义的。因此,这最终被LWG 问题 2116: is_nothrow_constructible and destructors\n覆盖,该问题尚未解决,因此这不是一个错误,除非该问题的解决方式与当前实现的行为方式不同。

\n\n

它以以下讨论开始:

\n\n
\n

IMO 如果我们根据变量声明指定 is_[nothrow_]constructible ,而其有效性需要可破坏性,那么这显然是我们规范中的一个错误,并且未能实现实际的原始意图。该规范应该是新的布局。

\n\n

Daniel:在制定规范时,这是有意为之的,并且解决方案并不是通过删除 is_constructible 的破坏语义来完成的。

\n\n

is_constructible 的设计也受到之前显式包含破坏语义的可构造概念的影响,因为在库的概念化过程中,它简化了库中的约束,因为您不需要添加 Destructible每时每刻。在 C++03 中,它经常是隐含的,但从未说出来。

\n\n

纯构造语义也被认为是有用的,因此 HasConstructor 也确实存在,并且肯定也可以作为特征使用。

\n\n

另一个经常被忽视的例子:这也会影响包装器类型,例如可能包含多个类型的对、元组、数组:如果您认为 T1 有一个已删除的析构函数,而 T2 有一个析构函数,那么这很容易理解可能抛出的构造函数:显然,\n 编译器可能需要在 std::pair 的\n 构造函数中使用 T1 的析构函数,以确保满足核心语言\n 要求(所有先前完全构造的子对象\n必须销毁)。

\n\n

核心语言也在 [class.copy] p11 中尊重了这一事实:

\n\n
\n


如果 X 具有: \n [\xe2\x80\xa6]
\n \xe2\x80\x94 ,则类 X 的默认复制/移动构造函数被定义为已删除 (9.4.3 [dcl.fct.def.delete])任何直接或虚拟基类或具有析构函数的类型的非静态数据成员,该析构函数已从默认构造函数中删除或无法访问
\n [\xe2\x80\xa6]

\n
\n\n

Dave:这尤其是关于 is_nothro_constructible 的。事实上,它因没有 noexcept dtor 而被挫败,这是一个缺陷。

\n
\n\n

它的结论是:

\n\n
\n

维尔希望“一个进化小组”来研究这个问题。

\n
\n\n

这个 gcc bug 报告来看,至少 gcc 将等待问题得到解决。

\n\n

另请参阅Non-trivial destructor make class non-trivially-constructible,其中涵盖了对相关问题的一些其他引用。另请注意此问题的 clang 错误

\n