请考虑以下代码:
#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。但总结the Standard:
如果满足以下所有条件,则类T的默认构造函数是微不足道的(即不执行任何操作):
- 构造函数不是用户提供的(即,是隐式定义或默认的)
- T没有虚拟成员函数
- T没有虚拟基类
- T没有使用默认初始值设定项的非静态成员。 (自C ++ 11起)
- T的每个直接基础都有一个普通的默认构造函数
- 类类型的每个非静态成员都有一个普通的默认构造函数
正如我所看到的,不依赖于析构函数的微不足道。
我错过了什么?是clang
bug吗?
我找到了一个解决方法:static_assert(__has_trivial_constructor( N ));
是内置类型特征。 clang
,gcc
和MSVC
支持。
对于is_noexcept_constructible
类型特征系列there is workaround也是如此。
答案 0 :(得分:6)
LWG issue 2116: std::swap noexcept(what?)中介绍了此问题,我们可以在std::is_trivially_default_constructible的cppreference部分看到这一点:
在许多实现中,is_nothrow_default_constructible还检查析构函数是否抛出,因为它实际上是noexept(T()):GCC bug 51452 LWG issue 2116
其中仅仅涉及is_nothrow_default_constructible
,但如果我们详细阅读该问题,我们也会看到它也适用于此。
如果我们首先引用gcc bug report: [DR 2116] has_nothrow_.*constructor bugs首先引用的话,那么也许会更容易:
检测nothrow可构造性的特征是错误的,因为它们受到对象是否具有不可靠性的影响;在noexcept(...)运算符的完整表达式的求值结束时调用destroy。他们都使用构建临时内部noexcept的模式,而他们应该使用placement new
这明确说明LWG问题中唯一真正提到的内容最终会说:
is_nothrow_constructible在is_constructible的术语中定义,通过查看假设变量并询问变量定义是否已知不会抛出异常来定义。该问题声称,在给定上下文的情况下,这也会检查类型的析构函数,因此如果析构函数可能抛出,则返回false。如果构造函数为noexcept(true)且析构函数为noexcept(false),则至少有一个实现(Howard's)会返回false。所以这不是一个紧张的解释。问题是要求使用placement new来定义它,而不是根据临时对象来定义,以便更清楚地表明is_nothrow_constructible只查看构造函数的noexcept状态,而不是析构函数。
也影响std::is_trivially_default_constructible
,is_constructible
依赖std::is_trivially_constructible与$employees = array(
123 => array(
'id' => 13,
'firstname' => 'Marky',
'lastname' => 'Mark'
),
213 => array(
'id' => 3,
'firstname' => 'Bobby',
'lastname' => 'Bob'
),
256 => array(
'id' => 42,
'firstname' => 'Jimmy',
'lastname' => 'Jim'
)
);
相同但又有以下限制:
但变量定义不会调用任何不重要的操作