std::bit_cast

来自cppreference.com
< cpp‎ | numeric
在标头 <bit> 定义
template< class To, class From >
constexpr To bit_cast( const From& from ) noexcept;
(C++20 起)

通过转译 from 的对象表示获得 To 类型的值。返回的 To 对象值表示中的每位都等于 from对象表示中的对应位。未指定返回的 To 对象中的填充位的值。

如果没有对应所产生的值表示的 To 类型值,那么行为未定义。如果有多个这种值,那么未指定产生哪个值。

以下情况下,结果的值表示中的某个位不确定

  • 这个位不对应 From 的值表示中的位(即它对应填充位),或
  • 这个位所在的对象 (C++26 前)的最小外围对象 (C++26 起)不在它的生存期内,或
  • 这个位具有不确定值

结果的值表示中的某个位在它对应的位的最小外围对象具有错误值的情况下错误

(C++26 起)


对于结果的值表示中的每个不确定位,含有该位的最小对象具有不确定值;如果该对象不具有未初始化友好类型,那么行为未定义。

其他情况下结果不含不确定值。

(C++26 前)

对于结果的值表示中的每个不确定位或错误位 b,给定 u 为包围 b 的最小对象:

  • 如果 u 具有未初始化友好类型,那么 u 在它的值表示中存在不确定位的情况下具有不确定值,否则具有错误值。
  • 否则,如果 b 不确定,那么行为未定义。
  • 否则,行为错误,并且结果与上述一致。

其他情况下结果不含不确定值或错误值。

(C++26 起)

此重载只有在 sizeof(To) == sizeof(From)ToFrom 两者都是可平凡复制 (TriviallyCopyable) 类型时才会参与重载决议。

此函数模板为 constexpr,当且仅当 ToFromToFrom 的所有子对象的类型都:

  • 不是联合体类型;
  • 不是指针类型;
  • 不是成员指针类型;
  • 不是 volatile 限定的类型;且
  • 没有引用类型的非静态数据成员。

参数

from - 返回值的位值源

返回值

具有如上所述值表示的 To 类型的对象。

可能的实现

要实现 std::bit_cast,如果忽略 constexpr,需要翻译对象表示为另一类型的对象表示时,可以使用 std::memcpy

template <class To, class From>
typename std::enable_if_t<
    sizeof(To) == sizeof(From) &&
    std::is_trivially_copyable_v<From> &&
    std::is_trivially_copyable_v<To>,
    To>
// constexpr 支持需要编译器魔法
bit_cast(const From& src) noexcept
{
    static_assert(std::is_trivially_constructible_v<To>,
        "此实现还要求目标类型可平凡默认构造");
 
    To dst;
    std::memcpy(&dst, &src, sizeof(To));
    return dst;
}

而实现 constexpr 可以尝试使用gcc内建函数:

template <class To, class From>
typename std::enable_if_t<
    sizeof(To) == sizeof(From) &&
    std::is_trivially_copyable_v<From> &&
    std::is_trivially_copyable_v<To>,
    To>
constexpr bit_cast(const From& from) noexcept
{
    return __builtin_bit_cast(_To, __from);
}

注解

因为类型别名使用规则,大多数情况下不应该用指针或引用类型间的 reinterpret_cast(或等价的显式转型)转译对象表示。

功能特性测试 标准 功能特性
__cpp_lib_bit_cast 201806L (C++20) std::bit_cast

示例

#include <bit>
#include <cstdint>
#include <iostream>
 
constexpr double f64v = 19880124.0;
constexpr auto u64v = std::bit_cast<std::uint64_t>(f64v);
static_assert(std::bit_cast<double>(u64v) == f64v); // 往返测试
 
constexpr std::uint64_t u64v2 = 0x3fe9000000000000ull;
constexpr auto f64v2 = std::bit_cast<double>(u64v2);
static_assert(std::bit_cast<std::uint64_t>(f64v2) == u64v2); // 往返测试
 
int main()
{
    std::cout
        << "std::bit_cast<std::uint64_t>(" << std::fixed << f64v << ") == 0x"
        << std::hex << u64v << '\n'
        << "std::bit_cast<double>(0x" << std::hex << u64v2 << ") == "
        << std::fixed << f64v2 << '\n';
}

可能的输出:

std::bit_cast<std::uint64_t>(19880124.000000) == 0x4172f58bc0000000
std::bit_cast<double>(0x3fe9000000000000) == 0.781250

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 2482
(P1272R4)
C++20 在涉及不确定位时未指定 UB 是否会出现 已指定

参阅

在给定的存储上创建对象并复用对象表示
(函数模板)