如何在 C++ 中制作模板函数来定义任何类型的位表示

问题描述 投票:0回答:1
template<typename T>
std::string bit_representation(T &&type) {
    uint8_t data[sizeof(T)];
    if constexpr (std::is_copy_constructible_v<T>) {
        T tmp(type);
        std::memcpy(&data, &tmp, sizeof(T));
    } else if (std::is_move_constructible_v<T>) {
        T tmp(std::move(type));
        std::memcpy(&data, &tmp, sizeof(T));
    }

    auto get_byte_repr = [](uint8_t byte) -> std::string {
        std::string s;
        constexpr size_t byte_size = sizeof(uint8_t) * 8;
        s.resize(byte_size);
        for (int i = byte_size - 1; i >= 0; --i) {
            s[i] = ((byte & 1) == 1) ? '1' : '0';
            byte >>= 1;
        }
        return s;
    };
    std::string result;

    for (int i = sizeof(T) - 1; i >= 0; --i) {
        result += get_byte_repr(data[i]);
    }
    return result;
}

我写了简单的

bit_representation
函数,对于简单的类型都很好,但我也想为pass写统一的模板函数
std::initializer_list<T>

    uint8_t u8 = 0xAF;
    std::cout << bit_representation(u8) << std::endl; // 10101111 ok
    std::cout << bit_representation((uint8_t) 0xAF) << std::endl; // 10101111 ok
    std::cout << bit_representation((short) 0xAF) << std::endl; // 0000000010101111 ok
    double d = 2.56;
    // 0100000000000100011110101110000101000111101011100001010001111011 = d its ok iee-754
    std::cout << bit_representation(d) << std::endl;
#pragma pack(1)
    struct {
        bool c = true;
        int a = 0x00FF00FF;
    } name;
#pragma pop()
    // 0000000011111111000000001111111100000001 // really ok
    std::cout << bit_representation(name) << std::endl; //  ok
    std::cout << bit_representation(true) << std::endl; // 00000001 ok
    std:cout << bit_representation({1,2,3,4}) << std::endl; /* error candidate template ignored: couldn't infer template argument 'T'
std::string bit_representation(T &&type) {*/

但是

bit_representation({1,2,3,4})
不工作.. 我需要编写 SFINAE 包装器以在编译时检测类型是否为
initializer_list<T>
.

我期待

bit_representation({1,2,3,4})
-> std::initializer_list 到内存 repr ->
00000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000001100000000000000000000000000000100

如何推导 std::inititalizer_list 参数并为此编写特殊逻辑。

c++ templates std sfinae bit-representation
1个回答
0
投票

std::initializer_list
有点特别。特别是(来自cppreference):

A

std::initializer_list
对象在以下情况下自动构造:

  • a braced-init-list 用于列表初始化对象,其中相应的构造函数接受
    std::initializer_list
    参数
  • 花括号初始化列表用作赋值的右操作数或函数调用参数,相应的赋值运算符/函数接受一个
    std::initializer_list
    参数
  • braced-init-list 绑定到 auto,包括在范围 for 循环中

bit_representation({1,2,3,4}) 
不是这些。
{1,2,3,4}
不是
std::initializer_list
。仅在某些情况下
{1,2,3,4}
会导致自动构建
std::initializer_list
。在所有其他情况下,
{1,2,3,4}
没有可以推导的类型。

您可以像这样用

std::initializer_list
调用函数:

bit_representation(std::initializer_list<int>{1,2,3,4});

此外,考虑任何对象都可以看作字节数组。不需要复制到数组。这是由于

char
byte
unsigned char
对于严格别名的例外情况,如此处解释:https://en.cppreference.com/w/cpp/language/reinterpret_cast。还不清楚为什么你的函数不直接使用它的参数
type
(相当误导的名称),而是在复制到数组之前进行另一个不必要的复制
tmp

这可能会给你一个更好的开始(未经测试):

std::string bit_representation(const T& t) {
       unsigned char* byte_repr = reinterpret_cast<unsigned char*>(&t);
       for (size_t i=0; i< sizeof(T); ++i) {
            byte_repr[i]; // <- i-th byte of t
            // ...
© www.soinside.com 2019 - 2024. All rights reserved.