[英]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.