我听说std::bit_cast
将在C ++ 20中使用,而对于结论是,实现它必然需要特殊的编译器支持感到有些困惑。
说句公道话,我听到的论点是该实现执行memcpy
操作,并且memcpy
通常不是constexpr
,而std::bit_cast
应该是,因此制作std::bit_cast
constexpr
要求编译器支持兼容constexpr
的{{1}}操作。
但是,我想知道是否有可能在不实际调用{{1的情况下}实现符合标准的memcpy
(即,定义的行为,与使用bit_cast
会具有定义的行为的程度相同) }}。
考虑以下代码:
memcpy
这里使用易失性成员来强制编译器发出必要的代码,以从成员中进行写入或读取,从而禁用优化,而我知道通常分配给一个联合的一个成员并从同一联合的另一个成员进行读取是由于未定义行为,C ++标准似乎允许从联合 IF 的任何成员中读取,该成员已从完全相同的联合的另一个实例按字节复制。在上面的代码中,这是通过在刚巧初始化memcpy
数据成员的新构造实例上显式调用默认副本构造函数来有效实现的。由于上述联合包含所有琐碎的类型,因此在其上调用默认副本构造函数就等于按字节复制,因此从新构造的实例的template<typename T, typename U>
inline constexpr T bit_cast(const U & x) noexcept {
static_assert(std::is_trivial<T>::value && std::is_trivial<U>::value, "Cannot use bit_cast with non-trivial data" );
static_assert(sizeof(T) == sizeof(U), "bit_cast must be used on identically sized types");
union in_out {
volatile U in;
volatile T out;
inline constexpr explicit in_out(const U &x) noexcept : in(x)
{
}
};
return in_out(in_out(x)).out;
}
成员进行读取不应仍然是未定义的行为,是吗?
当然,我完全有可能在这里遗漏一些非常明显的东西……我当然不能声称自己比制定这些标准的人更聪明,但是如果有人可以准确地告诉我我是哪种未定义的行为,在这里调用,我真的很想知道。
答案 0 :(得分:5)
在持续评估过程中,您不允许做的一件事是来自image states the error please check and help:
应用于左值的左值到右值转换,该值引用联合的非活动成员或其子对象;
您的实施方式是什么,因此这不是可行的实施策略。
答案 1 :(得分:2)
此处使用易失性成员来强制编译器发出必要的代码
如果您需要编写volatile
以确保编译器没有优化您的代码,则您的代码不正确。编译器无法修改有效代码的可观察行为。如果您想做的事情(没有volatile
)已定义为行为,则不允许编译器优化要使用volatile强制执行的写入和读取操作。
UB的事实是,您只被允许读取联盟的活动成员(在您的示例中为in
),但您读取了不活动的工会(在示例中为out
)。 / p>