代码之家  ›  专栏  ›  技术社区  ›  Ξένη Γήινος

如何使用索引序列展开循环?

  •  0
  • Ξένη Γήινος  · 技术社区  · 1 年前

    我试图尽可能有效地将无符号积分数据转换为内存中的二进制表示。

    我编写了四个模板函数来将整数转换为小端和大端,其中两个使用位运算,另外两个使用指针复制数据。

    它们被验证是正确的,而且非常有效,因为我已经确定little-endian函数的速度要快到 std::memcpy ,但是big-endian函数不知何故需要更长的时间。

    这些功能是:

    #include <vector>
    
    using std::vector;
    typedef vector<uint8_t> bytes;
    
    template<class T>
    inline bytes LittleEndian(const T& data) {
        size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t mask = 255;
        for (size_t i = 0, shift = 0; i < size; i++, shift += 8) {
            _bytes[i] = (data >> shift) & mask;
        }
        return _bytes;
    }
    
    template<class T>
    inline bytes BigEndian(const T& data) {
        size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t mask = 255;
        for (size_t i = size, shift = 0; i-- > 0; shift += 8) {
            _bytes[i] = (data >> shift) & mask;
        }
        return _bytes;
    }
    
    template<class T>
    inline bytes CPU_Endian(const T& data) {
        size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t* dst = (uint8_t *)_bytes.data(), * src = (uint8_t *) & data;
        for (size_t i = 0; i < size; i++) {
            *dst++ = *src++;
        }
        return _bytes;
    }
    
    template<class T>
    inline bytes Flip_CPU_Endian(const T& data) {
        size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t* dst = (uint8_t *)_bytes.data(), * src = (uint8_t *)&data + size - 1;
        for (size_t i = 0; i < size; i++) {
            *dst++ = *src--;
        }
        return _bytes;
    }
    

    我想使用展开for循环 std::index_sequence ,因为它们是相关的,所以我把它们放在一个问题中。它们大约有三件事:重复做一件事N次,制作一个减少而不是增加的索引序列,以及使用索引来设置值。

    我试过自己做,但没用:

    template<class T>
    inline bytes CPU_Endian2(const T& data) {
        size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t* dst = (uint8_t*)_bytes.data(), * src = (uint8_t*)&data;
        [&]<std::size_t...N>(std::index_sequence<N...>){
            ((*dst++ = *src++),...);
        }(std::make_index_sequence<size>{});
        return _bytes;
    }
    

    它没有编译,错误日志:

    Build started at 18:54...
    1>------ Build started: Project: hexlify_test, Configuration: Release x64 ------
    1>hexlify_test.cpp
    1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(98,3): error C7515: a fold expression must contain an unexpanded parameter pack
    1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,3): error C3878: syntax error: unexpected token '(' following 'expression'
    1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,3): message : error recovery skipped: '( identifier ::  . . . {'
    1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,35): error C2760: syntax error: '}' was unexpected here; expected ';'
    1>Done building project "hexlify_test.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    ========== Build completed at 18:54 and took 01.796 seconds ==========
    

    如何将这些函数转换为使用 std::index_sequence 而不是循环?


    正在添加 constexpr size_t size = sizeof(T); 未能使其编译。

    1 回复  |  直到 1 年前
        1
  •  2
  •   Jarod42    1 年前

    您有两个问题:

    size 不是 constexpr ,因此不能用作模板参数。

    -> constexpr size_t size = sizeof(T);

    你的fold表达式不使用任何pack

    所以要么

    (((*dst++ = *src++), static_cast<void>(Is)), ...);
    

    ((dst[Is] = src[Is]),...);
    

    合在一起,就会

    template<class T>
    bytes CPU_Endian2(const T& data) {
        constexpr size_t size = sizeof(T);
        bytes _bytes(size);
        uint8_t* dst = (uint8_t*)_bytes.data(), * src = (uint8_t*)&data;
        [&]<std::size_t...Is>(std::index_sequence<Is...>){
            ((dst[Is] = src[Is]), ...);
        }(std::make_index_sequence<size>{});
        return _bytes;
    }
    

    Demo