[英]Can C++14 standard-layout types use `alignas` for fields?
我想使用模板来简化具有非平凡类型的联合的构造。 以下似乎在实践中“起作用”,但在规范上技术上并不合法:
template<typename T> struct union_entry {
void (*destructor_)(void *); // how to destroy type T when active
T value_;
};
union U {
union_entry<A> a;
union_entry<B> b;
// ... some constructor and destructor...
};
问题在于(根据N4141),只有当两个结构都是标准布局类型时,才能访问联合中两个结构的公共初始序列(即destructor_
字段) - 至少根据非规范性说明9.5.1。 根据9.0.7,标准布局类型不能具有任何具有非标准布局的非静态数据成员。 因此,如果A或B不是标准布局,那么在错误的并集中访问destructor_
就变得非法。
漏洞似乎是通过将value_
in转换为alignas(T) char[sizeof(T)]
来制作union_entry
标准布局。 9.0.7中的任何内容似乎都不排除使用alignas
。 因此,我的问题是 : 对于任何类型T
,以下是标准布局类型吗? 因此可以将value_
转换为T&
以模拟前面的示例,同时仍允许destructor_
用于非活动的union_entry
?
template<typename T> struct union_entry {
void (*destructor_)(void *);
alignas(T) char value_[sizeof(T)];
}
在clang-3.8.1和g ++ - 6.2.1中, std::is_standard_layout
表明union_entry<T>
是标准布局,即使T
不是。 这是一个完整的工作示例,说明我将如何使用此技术:
#include <cassert>
#include <iostream>
#include <new>
#include <string>
using namespace std;
template<typename T> struct union_entry {
void (*destructor_)(void *);
alignas(T) char value_[sizeof(T)];
union_entry() : destructor_(nullptr) {}
~union_entry() {} // Just to cause error in unions w/o destructors
void select() {
if (destructor_)
destructor_(this);
destructor_ = destroy_helper;
new (static_cast<void *>(value_)) T{};
}
T &get() {
assert(destructor_ == destroy_helper);
return *reinterpret_cast<T *>(value_);
}
private:
static void destroy_helper(void *_p) {
union_entry *p = static_cast<union_entry *>(_p);
p->get().~T();
p->destructor_ = nullptr;
}
};
union U {
union_entry<int> i;
union_entry<string> s;
U() : i() {}
~U() { if (i.destructor_) i.destructor_(this); }
};
int
main()
{
U u;
u.i.select();
u.i.get() = 5;
cout << u.i.get() << endl;
u.s.select();
u.s.get() = "hello";
cout << u.s.get() << endl;
// Notice that the string in u.s is destroyed by calling
// u.i.destructor_, not u.s.destructor_
}
感谢@Arvid,他指向我std::aligned_storage
,我相信标准的第20.10.7.6节中有一个明确的(尽管是非规范的)答案(我假设与N4141相同)。
首先,表57说明aligned_storage
“成员type
应为POD类型 ...”,其中9.0.10表明“POD结构是一个非联合类,既是一个普通类, 也是一个标准布局类 “。
接下来,20.10.7.6.1给出了一个非规范的示例实现:
template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
typedef struct {
alignas(Alignment) unsigned char __data[Len];
} type;
};
很明显,使用alignas
并不能防止类型成为标准布局。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.