例如,据我所了解,内置类型、内置类型元组和此类元组的元组都属于此类别。动机是我希望在可能的情况下传输原始字节。
T t1(...); // not necessarely default constructible
T t2(...);
t1 = t2; // should be equivalent to std::memcpy(&t1, &t2, sizeof(T));
// t1 is now an (independent) copy of the value of t2, for example each can go out of scope independently
什么type_trait
或者type_traits的组合可以在编译时告诉我们是否可以使用memcpy
替换赋值操作?
我尝试了适用于我猜测应该满足此条件的类型,并且令我惊讶的是,唯一符合行为的选项不是std::is_trivially_assignable
而是std::trivially_destructible
。某种程度上来说这是有道理的,但我感到困惑的是一些其他选项在预期的情况下为何不起作用。
我知道可能没有绝对可靠的方法,因为总是可以编写一个实际上是可以通过memcopy进行拷贝的类,但无法被"检测"为可拷贝,但我正在寻找适用于简单直观情况的方法。
#include<type_traits>
template<class T> using trait =
std::is_trivially_destructible
// std::is_trivial
// std::is_trivially_copy_assignable
// std::is_trivially_copyable // // std::tuple<double, double> is not trivially copyable!!!
// std::is_trivially_default_constructible
// std::is_trivially_default_constructible
// std::is_trivially_constructible
// std::is_pod // std::tuple<double, double> is not pod!!!
// std::is_standard_layout
// std::is_aggregate
// std::has_unique_object_representations
<T>
;
int main(){
static_assert((trait<double>{}), "");
static_assert((trait<std::tuple<double, double>>{}), "");
static_assert((not trait<std::tuple<double, std::vector<double>>>{}), "");
static_assert((not trait<std::vector<double>>{}), "");
}
当然,我认为元组应该是可复制的,并不是基于标准,而是基于常识和实践。也就是说,因为这通常是可以的:
std::tuple<double, std::tuple<char, int> > t1 = {5.1, {'c', 8}};
std::tuple<double, std::tuple<char, int> > t2;
t2 = t1;
std::tuple<double, std::tuple<char, int> > t3;
std::memcpy(&t3, &t1, sizeof(t1));
assert(t3 == t2);
作为原理证明,我实现了这个功能。
std::tuple
特化误导的情况。template<class T>
struct is_memcopyable
: std::integral_constant<bool, std::is_trivially_copyable<T>{}>{};
template<class T, class... Ts>
struct is_memcopyable<std::tuple<T, Ts...>> :
std::integral_constant<bool,
is_memcopyable<T>{} and is_memcopyable<std::tuple<Ts...>>{}
>
{};
template<class T1, class T2>
struct is_memcopyable<std::pair<T1, T2>> :
std::integral_constant<bool,
is_memcopyable<T1>{} and is_memcopyable<T2>{}
>
{};
这只是一个非常有限的解决方案,因为像以下这样的类:
struct A{ std::tuple<double, double> t; };
遗憾的是,它仍然会被报告为非平凡可复制和非内存复制。
std::pair
的赋值运算符没有默认值...所以也许你应该建议标准修复这个问题...同时,即使它可能按预期工作,我会尽量避免依赖UB。 - Phil1970