bit_cast 没有编译器支持 constexpr memcpy 可能吗?

is bit_cast without compiler support for constexpr memcpy possible?

听说std::bit_cast会出现在C++20中,对于实现它必然需要特殊编译器支持的结论我有点疑惑

公平地说,我听到的说法是该实现执行了一个 memcpy 操作,而 memcpy 通常不是 constexpr,而 std::bit_cast 应该是是的,因此使 std::bit_cast constexpr 据说需要编译器支持 constexpr 兼容的 memcpy 操作。

不过,我想知道是否有可能在不实际调用 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;
}

此处使用可变成员来强制编译器发出必要的代码,这些代码将写入成员或从成员读取,禁用优化,而我知道通常分配给联合的一个成员并从同一成员读取另一个成员union 是未定义的行为,C++ 标准似乎允许从 union IF 的任何成员读取它已从完全相同的 union 的另一个实例按字节复制。在上面的代码中,这是通过在恰好初始化 in 数据成员的新构造实例上显式调用默认复制构造函数来有效实现的。由于上面的 union 包含所有普通类型,调用它的默认复制构造函数相当于按字节复制,所以从新构造的实例的 out 成员读取不应该仍然是未定义的行为,不是吗?

当然,我完全有可能在这里遗漏了一些非常明显的东西......我当然不能声称比制定这些标准的人更聪明,但如果有人能准确地告诉我哪个未定义我在这里调用的行为,我真的很想知道它。

在持续评估期间你不能做的事情之一是,来自 [expr.const]/4.9:

an lvalue-to-rvalue conversion that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;

您的实施是做什么的,因此它不是可行的实施策略。

Volatile members are used here to force the compiler to emit the necessary code

如果您需要编写 volatile 以确保编译器不会优化您的代码,那么您的代码不正确。编译器无法修改有效代码的可观察行为。如果你想做的事情(sans volatile)已经被定义为行为,编译器将不会被允许优化你想要用 volatile 强制执行的写入和读取。

UB 来自这样一个事实,即您只被允许读取联合的活跃成员(在您的示例中为 in),但您读取了不活跃的成员(在您的示例中为 out) .