要么是我的错误,要么是我被错误引用了,老实说,我不记得是哪一个。
但是,我对此主题有以下非常强烈的建议:
请勿使用is_trivial 或is_trivially_copyable!永远!!!
改为使用以下之一:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
理由:
tldr:看到这个excellent question and correct answer.
没有人(包括我自己)能记住is_trivial 和is_trivially_copyable 的定义。如果你碰巧查了一下,然后花 10 分钟分析它,它可能会也可能不会像你直觉认为的那样做。如果您设法正确分析它,CWG 很可能会在很少或根本不通知的情况下更改其定义,并使您的代码无效。
使用is_trivial 和is_trivially_copyable 是在玩火。
但是这些:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
做他们听起来像他们做的事情,并且不太可能改变他们的定义。必须单独处理每个特殊成员似乎过于冗长。但它会在代码的稳定性/可靠性方面得到回报。如果必须,将这些单独的特征打包成一个自定义特征。
更新
例如,clang & gcc 编译这个程序:
#include <type_traits>
template <class T>
void
test()
{
using namespace std;
static_assert(!is_trivial<T>{}, "");
static_assert( is_trivially_copyable<T>{}, "");
static_assert( is_trivially_destructible<T>{}, "");
static_assert( is_destructible<T>{}, "");
static_assert(!is_trivially_default_constructible<T>{}, "");
static_assert(!is_trivially_copy_constructible<T>{}, "");
static_assert( is_trivially_copy_assignable<T>{}, "");
static_assert(!is_trivially_move_constructible<T>{}, "");
static_assert( is_trivially_move_assignable<T>{}, "");
}
struct X
{
X(const X&) = delete;
};
int
main()
{
test<X>();
}
请注意,X 是可简单复制的,但不是可简单复制构造的。据我所知,这是符合规范的行为。
VS-2015 目前表示X既不可简单复制也不可简单复制构造。根据目前的规范,我认为这是错误的,但它确实符合我的常识。
如果我需要memcpy 来未初始化内存,我会相信is_trivially_copy_constructible 而不是is_trivially_copyable 向我保证这样的操作是可以的。如果我想memcpy 来初始化内存,我会检查is_trivially_copy_assignable。