确定在编译时使用reinterpret_cast是否安全

3
根据cppreference.com上的reinterpret_cast页面,除了会转换掉constnessvolatility之外,可以使用11种转换方式进行reinterpret_cast。那么,我的问题是:是否可能编写像这样的constexpr函数?
template <typename T1, typename T2>
constexpr bool is_reinterpret_cast_safe() {
    // ...
}

根据这11个点检查转换是否允许?由于编译器(如GCC和Clang)能够检查代码是否违反严格别名规则,因此使用-fstrict-aliasing -Wstrict-aliasing编译,我认为应该可以以某种方式实现。

我知道C++20引入了std::bit_cast, 但目前还没有任何编译器支持。在编译时选择两个转换函数可能会很有用。

template <typename T1, typename T2>
T1 f_reinterpret_cast(T2 d) {
    static_assert(sizeof(T1) == sizeof(T2));
    return *reinterpret_cast<T1*>(&d); // could be undefined behavior;
}

template <typename T1, typename T2>
T1 f_memcpy(T2 d) {
    static_assert(sizeof(T1) == sizeof(T2));
    T1 n;
    std::memcpy(&n, &d, sizeof(T2)); // OK
    return n;
}

使用SFINAE或if constexpr:

template <typename T1, typename T2>
T1 conv(T2 d) {
    if constexpr (is_reinterpret_cast_safe<T1, T2>())
        return conv_reinterpret_cast<T1, T2>(d);
    else
        return conv_memcpy<T1, T2>(d);
}

您可以在https://godbolt.org/z/Ex6GnP上找到代码。


你开始写了吗?卡住了吗? Cppreference 很好地列出了所有的情况,因此至少有一些点很容易解决,例如对于第一个伪代码:if ((std::is_integral<T1> || std::is_enum<T1> || std::is_pointer<T1> || std::is_member_object_pointer<T1>) && std::is_same<T1, T2>) return true; - KamilCuk
你为什么想要避免使用 std::memcpy 函数? - Acorn
@Acorn 主要是出于好奇心。 - Giovanni Cerretani
1个回答

1
编译器在编译时检查reinterpret_cast表达式的有效性:当访问对象时可能会违反别名规则。
int i = 0;                                   //OK
double j* = reinterpret_cast <double*> (i);  //OK
double k = *j;                               //strict aliasing violation

无法检查 reinterpret_cast 是否会导致指针无法用于访问其所指向的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接