簡體   English   中英

C ++ 14 constexpr在構造函數中的條件初始化

[英]C++14 constexpr union conditional initialization in constructor

我想根據參數選擇在構造函數中初始化的union成員。 以下是一個有效的示例:

struct A {
    union {
        int i;
        float f;
    };
    A(double d, bool isint) {
        if (isint) new(&i) int(d);
        else new(&f) float(d);
    }
};

當我使用intfloat ,目標是使用其他更復雜的類型(但仍然允許在C ++ 14聯合中使用),因此使用placement-new(而不是賦值)。

問題是這個構造函數不能是constexpr因為constexpr方法中不允許使用placement-new。 有沒有辦法解決這個問題(除了使isint參數成為正式類型系統的一部分)? 某種類型的條件初始化列表可以工作,但我不知道有辦法做到這一點。

有一個技巧。 關鍵部分是:

  1. 聯合的默認副本或移動構造函數復制對象表示(從而復制活動成員),並且在常量表達式求值中是允許的。
  2. 初始化完成后,您無法在常量表達式求值中更改活動聯合成員,但您可以委托另一個構造函數來延遲選擇。
  3. 如果委派給復制或移動構造函數,則可以傳入另一個已初始化為正確狀態的對象並復制其活動成員。

把它們放在一起,我們得到:

template<typename T> struct tag {};
struct A {
  union {
    int i;
    float f;
  };
  constexpr A(tag<int>, double d) : i(d) {}
  constexpr A(tag<float>, double d) : f(d) {}
  constexpr A(double d, bool isint) : A(isint ? A(tag<int>(), d) : A(tag<float>(), d)) {}
};

constexpr A a(1.0, true); // ok, initializes 'i'
constexpr A b(5, false);  // ok, initializes 'f'

這是最近的Clang,GCC和EDG所接受的,並且只需要C ++ 11 constexpr

警告: GCC 5.1.0有一個錯誤,它錯誤地編譯了上面的代碼(將ab初始化為0 ); GCC的早期版本或更高版本中不存在此錯誤。

對於簡單的可構造對象,不需要new 您可以開始對象生存期,並只需通過賦值運算符選擇活動的union成員。

struct A {
    union {
        int i;
        float f;
    };
    A(double d, bool isint) {
        if (isint) i = d;
        else f = d;
    }
};

如果成員中某處有構造函數,那么就必須使用Richard的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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