宽松常量表达式中联合非活动成员的左值到右值转换的解决方法

gnz*_*lbg 4 c++ unions constexpr c++14

触发联合非活动成员的左值到右值转换不是常量表达式。也就是说,给定union

template<class T, class U>
union A {
  constexpr A(T t) : t_{t} {}
  constexpr A(U u) : u_{u} {}
  T t_;
  U u_;
};
Run Code Online (Sandbox Code Playgroud)

constexpr功能foo

template<class T, class U>
constexpr auto foo() {
  A<T, U> a(T{});
  return a.u_;
}
Run Code Online (Sandbox Code Playgroud)

以下程序:

int main() {
  constexpr auto test = foo<int, double>();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

失败并显示错误消息:

error: constexpr variable 'test' must be initialized by a
      constant expression
  constexpr auto test = foo<int, double>();
                 ^      ~~~~~~~~~~~~~~~~~~
note: read of member 'u_' of union with active member 't_' is
      not allowed in a constant expression
  return a.u_;
         ^
note: in call to 'foo()'
  constexpr auto test = foo<int, double>();
                        ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

是否有解决方法可以在 C++14 的常量表达式中实现此行为?reinterpret_cast也不被允许。

动机:我正在尝试将 google-test 的浮点比较实用程序设为 constexpr。

Ric*_*ith 5

不,在 C++14 中无法在常量表达式中进行类型双关。除了常量表达式之外也没有办法做到这一点;您显示的代码在运行时将具有未定义的行为。

作为一般情况下不允许这样做的示例,请考虑以下内容:

union U { int *p; size_t n; };
int a;
constexpr U u = { &a };
static_assert(u.n != 0x400e158, "'a' is at my favourite address");
Run Code Online (Sandbox Code Playgroud)

如果允许,则需要一个实现来确定a编译期间的运行时地址。