C++14标准布局类型是否可以对字段使用“alignas”
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_
转换为alignas(T) char[sizeof(T)]
来制作union_entry
标准布局。9.0.7中的任何内容似乎都不排除使用alignas
。因此,我的问题是:以下是任何类型T
的标准布局类型吗因此,是否可以将value_
强制转换为T&
以模拟前面的示例,同时仍然允许在非活动union_entry
中使用destructor_
?
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
"成员typedef 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
的使用并不能阻止一个类型成为标准布局。
- 将结构字段的类型展开为可变模板参数
- 将位字段导出到数组
- 为了方便起见,我应该避免公开私有字段变量吗
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- 在java中读取c++字节的位字段
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 私有字段对象与私有继承?
- 声明没有默认构造函数的字段
- C++内存模型和位字段的最大序列
- 声明为无效的变量或字段'...' Ardunio 编译器上的错误
- 如何在QByteArray中放置和检索位字段而不会感到痛苦?
- C++ win32 如何使密码字段可选并启用复制和粘贴?
- 如何通过UDP接收QByteArray并将其解析为位字段结构?
- 仅匹配集合中的某些字段
- 结构字段名称与 GDB 中的 STL 数组冲突
- 如何使用位字段将数据从二进制文件复制到结构中?
- 结构体和类的不同大小(),彼此具有相同的字段类型
- 如何避免在数据结构中包含存储为字段的类?
- 聚合初始化和删除的复制构造函数,也称为不可复制的 obejcts 作为字段
- C++14标准布局类型是否可以对字段使用“alignas”