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

How to make a template function in C++ to define a bit representation of any type

提问人:vanyabeat 提问时间:4/25/2023 最后编辑:vanyabeat 更新时间:4/25/2023 访问量:78

问:

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

我写了简单的函数,对于简单的类型都很好,但我也想为pass编写统一的模板函数。bit_representationstd::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) {*/

但不起作用.. 我需要编写 SFINAE 包装器来检测编译时是否为 .bit_representation({1,2,3,4})initializer_list<T>

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

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

C++ 模板 std sfinae 位表示

评论

0赞 463035818_is_not_an_ai 4/25/2023
“not working” 是什么意思?
4赞 463035818_is_not_an_ai 4/25/2023
{1,2,3,4}没有可以推断的类型。
0赞 vanyabeat 4/25/2023
错误:调用“bit_representation”没有匹配函数bit_representation({1,2,3,4});
0赞 463035818_is_not_an_ai 4/25/2023
请发布一个最小的可重复示例。如果我想写一个答案,我必须从这个开始:godbolt.org/z/Gzqh53K8j,但你确实有编译的代码(除了一个错误),请发布它{1,2,3,4}
0赞 vanyabeat 4/25/2023
@463035818_is_not_a_number我无法在编译时推断出 std::initializer_list<T>。

答:

1赞 463035818_is_not_an_ai 4/25/2023 #1

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

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

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

bit_representation({1,2,3,4}) 都不是这些。 不是 .只有在某些上下文中,才能自动构造 a。在所有其他上下文中,没有可以推导出的类型。{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});

此外,考虑到任何对象都可以被视为字节数组。无需复制到数组。这是由于 和 严格别名的例外,如下所述:https://en.cppreference.com/w/cpp/language/reinterpret_cast。目前还不清楚为什么您的函数不直接使用其参数(相当具有误导性的名称),而是在复制到数组之前进行另一个不必要的复制。charbyteunsigned chartypetmp

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

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
            // ...

评论

0赞 vanyabeat 4/25/2023
谢谢我写新函数
0赞 vanyabeat 4/25/2023
它很疯狂,但它有效,我添加了重载的定义cpp template<typename T> std::string bit_representation(std::initializer_list<T> ilist) { std::string result; for (const auto item: ilist) { result += bit_representation(item); } return result; }
1赞 Fabian Keßler 4/25/2023
他可以将流运算符重载为 std::byte,并且只返回 std::byte 的范围。c++ 标准还定义了 std::as_bytes
0赞 463035818_is_not_an_ai 4/25/2023
@vanyabeat什么是疯狂的?
0赞 463035818_is_not_an_ai 4/25/2023
@FabianKe ßler:是的,C++20 中有更好的功能。但是,如果没有其他标记,我假设 c++17,也是因为我不流利地使用 c++20。而且我的印象是 OP 想要一些自制的东西,但我可能是错的
0赞 vanyabeat 4/25/2023 #2

最后,这个解决方案出现了,但我不确定它是否是正确的解决方案

template<typename T>
std::string bit_representation(T &&type) {
    auto ptr = reinterpret_cast<const uint8_t *>(&type);
    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(ptr[i]);
    }
    return result;
}

template<typename T>
std::string bit_representation(std::initializer_list<T> ilist) {
    std::string result;
    for (const auto item: ilist) {
        result += bit_representation(item);
    }
    return result;
}

输出

    unsigned short carr[] = {0xDEAD, 0xBEEF};
    struct mZ {
        mZ(uint8_t value) {
            auto ptr = reinterpret_cast<uint8_t *>(this);
            std::fill(ptr, ptr + 1, value);
        }

        mZ() = delete;

        mZ(const mZ &o) = delete;

        mZ(mZ &&o) = default;

        uint8_t a: 1;
        uint8_t b: 1;
        uint8_t c: 1;
        uint8_t d: 1;
        uint8_t e: 1;
        uint8_t f: 1;
        uint8_t g: 1;
        uint8_t h: 1;
    };
    
    /*1111111110101010*/
    std::cout << bit_representation((short) 0xFFAA) << std::endl;
    /*11111110*/
    std::cout << bit_representation(mZ(254)) << std::endl;
    /*00000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000001100000000000000000000000000000100*/
    std::cout << bit_representation({1, 2, 3, 4}) << std::endl;
    /*10111110111011111101111010101101*/
    std::cout << bit_representation(carr) << std::endl;

评论

0赞 vanyabeat 4/25/2023
@463035818_is_not_a_number