设S
为结构类型,其中包含具有最大对齐和固定大小的字符数组data
。我们的想法是S
能够存储任何类型T
的对象,其大小不超过限制,并且可以简单地复制构造并且可以轻易破坏。
static constexpr std::size_t MaxSize = 16;
struct S {
alignas(alignof(std::max_align_t)) char data[MaxSize];
};
Placement-new用于将T
类型的对象构造到新S
对象的字符数组中。然后,该对象被复制任意次,包括返回并按值传递。
template <typename T>
S wrap(T t) {
static_assert(sizeof(T) <= MaxSize, "");
static_assert(std::is_trivially_copy_constructible_v<T>, "");
static_assert(std::is_trivially_destructible_v<T>, "");
S s;
new(reinterpret_cast<T *>(s.data)) T(t);
return s;
}
稍后给出此S
值的副本,reinterpret_cast
用于从指向字符数组开头的指针获取T*
,然后T
对象以某种方式访问。 T
类型与创建值时的类型相同。
void access(S s) {
T *t = reinterpret_cast<T *>(s.data);
t->print();
}
我想知道这个方案中是否有任何未定义的行为以及它将如何解决。例如,我担心:
std::launder
旨在解决的问题?在构造data
的实例后,我不确定将T
作为字符数组访问是否有效。我是否需要在访问值的位置std::launder
,以及为什么?S
复制构造函数是否存在复制data
中所有字节的问题,因为某些字节可能尚未初始化?我担心sizeof(T)
以外的字节以及T
对象中可能未初始化的字节(例如填充)。我的用例是实现一个非常轻量级的多态函数包装器,它能够与满足我为T
列出的那些要求的任何可调用函数一起使用。
答案 0 :(得分:0)
THE TERM has a long definition that may run
on for quite some time.
这可能是有用的。它将编译器对数据的解释从一种pod类型转换为另一种pod类型,并在优化下编译为noop。
所以把你的缓冲区,洗衣荚拿到T,写到它,洗衣荚回到gdneric存储。阅读,洗衣舱到T.请注意,所有通过T指针写入后应将其清洗回通用存储,以避免使用别名规则来优化掉看似丢弃的ptr上的写入。