简体   繁体   English

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

[英]is bit_cast without compiler support for constexpr memcpy possible?

I had heard that std::bit_cast will be in C++20, and I am slightly puzzled about the conclusion that implementing it necessarily requires special compiler support.我听说std::bit_cast将在 C++20 中,我对实现它必然需要特殊编译器支持的结论感到有些困惑。

To be fair, the argument I have heard is that the implementation performs a memcpy operation, and memcpy is not typically constexpr , while std::bit_cast is supposed to be, so making std::bit_cast constexpr supposedly requires compiler support for a constexpr -compliant memcpy operation.公平地说,我听到的论点是实现执行memcpy操作,而memcpy通常不是constexpr ,而std::bit_cast应该是,所以制作std::bit_cast constexpr应该需要编译器支持constexpr -兼容的memcpy操作。

I was wondering, however, if it was possible to implement a compliant bit_cast (ie, defined behavior, to same extent that using memcpy would have had defined behavior) without actually invoking memcpy at all.但是,我想知道是否可以在根本不实际调用memcpy的情况下实现兼容的bit_cast (即,定义的行为,与使用memcpy具有定义的行为的程度相同)。

Consider the following code:考虑以下代码:

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;
}

Volatile members are used here to force the compiler to emit the necessary code that would write or read from the members, disabling optimizations, and while I know ordinarily assigning to one member of a union and reading from another in the same union is undefined behavior, the C++ standard does appear to allow reading from any member of a union IF it has been bytewise copied from another instance of the exact same union.易失性成员在这里用于强制编译器发出必要的代码,这些代码将从成员中写入或读取,禁用优化,虽然我知道通常分配给联合的一个成员并从同一个联合中的另一个成员读取是未定义的行为, C++ 标准似乎允许从联合的任何成员读取,如果它是从完全相同的联合的另一个实例按字节复制的。 In the above code, this is effectively accomplished by explicitly calling the default copy constructor on the newly constructed instance that happens to intialize the in data member.在上面的代码中,这可以通过在恰好初始化in数据成员的新构造实例上显式调用默认复制构造函数来有效地完成。 Since the above union contains all trivial types, calling the default copy constructor on it amounts to a bytewise copy, so reading from the out member of the newly constructed instance should not still be undefined behavior, should it?由于上述联合包含所有普通类型,因此对其调用默认复制构造函数相当于按字节复制,因此从新构造的实例的out成员中读取不应该仍然是未定义的行为,不是吗?

Of course, it's entirely possible that I'm missing something extremely obvious here... I certainly can't claim to be any smarter than the people who develop these standards, but if someone can tell me exactly which undefined behavior I am invoking here, I'd really like to know about it.当然,我完全有可能在这里遗漏了一些非常明显的东西......我当然不能声称比制定这些标准的人更聪明,但是如果有人能准确地告诉我我在这里调用了哪些未定义的行为,我真的很想知道。

One of the things you're not allowed to do during constant evaluation is, from [expr.const]/4.9 :[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;左值到右值的转换,应用于引用联合或其子对象的非活动成员的左值;

Which is what your implementation does, so it's not a viable implementation strategy.这就是您的实施所做的,因此它不是一个可行的实施策略。

Volatile members are used here to force the compiler to emit the necessary code这里使用易失性成员来强制编译器发出必要的代码

If you need to write volatile to make sure the compiler doesn't optimize out your code then your code is not ok.如果您需要编写volatile以确保编译器不会优化您的代码,那么您的代码就不行。 A compiler cannot modify the observable behavior of a valid code.编译器无法修改有效代码的可观察行为。 If what you wanted to do (sans volatile ) would have been defined behavior, the compiler would not have been allowed to optimize out the writes and reads you want to force with volatile.如果您想要做的事情(无volatile )将被定义为行为,则不允许编译器优化您想要使用 volatile 强制执行的写入和读取。

The UB comes from the fact that you are only allowed to read the active member of an union ( in in your example) but you read the inactive one ( out in your example). UB 来自这样一个事实,即您只被允许阅读工会的活动成员( in您的示例中),但您阅读了非活动成员( out您的示例中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM