C ++ 14 constexpr在构造函数中的条件初始化

时间:2015-06-03 23:15:53

标签: c++ c++14 unions constexpr

我想根据参数选择在构造函数中初始化的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参数成为正式类型系统的一部分)?某种类型的条件初始化列表可以工作,但我不知道如何做到这一点。

2 个答案:

答案 0 :(得分:7)

There is a trick. The key pieces are:

  1. A defaulted copy or move constructor for a union copies the object representation (and thus copies the active member), and is permitted in constant expression evaluation.
  2. You cannot change the active union member in a constant expression evaluation after initialization is complete, but you can delegate to another constructor to delay the choice.
  3. If you delegate to the copy or move constructor, you can pass in another object that is already initialized to the right state and copy its active member.

Putting this together, we get:

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'

This is accepted by recent Clang, GCC, and EDG, and requires only C++11 constexpr.

Warning: GCC 5.1.0 had a bug where it miscompiled the above code (initializing a and b to 0); this bug is not present in earlier or later versions of GCC.

答案 1 :(得分:1)

对于简单的可构造对象,不需要new。您可以开始对象生存期,并只需通过赋值运算符选择活动的union成员。

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

如果会员内部某处有构造函数,那么使用理查德的答案是必要的。