簡體   English   中英

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_ 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM