非平凡的析构函数使 class 非平凡可构造

Non-trivial destructor make class non-trivially-constructible

考虑以下代码:

#include <type_traits>

struct T {};

static_assert(std::is_trivially_destructible< T >{});
static_assert(std::is_trivially_default_constructible< T >{});

struct N { ~N() { ; } };

static_assert(!std::is_trivially_destructible< N >{});
static_assert(!std::is_trivially_default_constructible< N >{});

使用 clang 3.7.0 可以很好地编译:live example. But summarizing the Standard:

The default constructor for class T is trivial (i.e. performs no action) if all of the following is true:

  • The constructor is not user-provided (i.e., is implicitly-defined or defaulted)
  • T has no virtual member functions
  • T has no virtual base classes
  • T has no non-static members with default initializers. (since C++11)
  • Every direct base of T has a trivial default constructor
  • Every non-static member of class type has a trivial default constructor

如我所见,不依赖于析构函数的琐碎性。

我错过了什么?是 clang 错误吗?

额外的

我找到了一个解决方法:static_assert(__has_trivial_constructor( N )); 内置类型特征。 clang, gcc and MSVC.

中有支持

is_noexcept_constructible 类型特征家族 there is workaround

这个问题在 LWG issue 2116: std::swap noexcept(what?), we can see this from the cppreference section for std::is_trivially_default_constructible:

In many implementations, is_nothrow_default_constructible also checks if the destructor throws because it is effectively noexept(T()): GCC bug 51452 LWG issue 2116

这看似只谈论 is_nothrow_default_constructible 但如果我们详细阅读该问题,我们会发现它也适用于此。

如果我们按照第一个引用的 gcc bug report: [DR 2116] has_nothrow_.*constructor bugs 说:

,也许会更容易

The traits that detect nothrow constructibility are buggy because they are influenced by whether the object has a nothrow dtor; destruction is invoked at the end of evaluation of the full expression in the noexcept( ... ) operator. They all use the pattern of constructing a temporary inside noexcept, whereas they should be using placement new

这明确说明了 LWG 问题中真正提到的内容,最终说:

is_nothrow_constructible is defined in terms of is_constructible, which is defined by looking at a hypothetical variable and asking whether the variable definition is known not to throw exceptions. The issue claims that this also examines the type's destructor, given the context, and thus will return false if the destructor can potentially throw. At least one implementation (Howard's) does return false if the constructor is noexcept(true) and the destructor is noexcept(false). So that's not a strained interpretation. The issue is asking for this to be defined in terms of placement new, instead of in terms of a temporary object, to make it clearer that is_nothrow_constructible looks at the noexcept status of only the constructor, and not the destructor.

也影响 std::is_trivially_default_constructible,它依赖于 std::is_trivially_constructible,它与 is_constructible 的作用相同,但有进一步的限制:

but the variable definition does not call any operation that is not trivial