Как использовать индексную последовательность для развертывания циклов?

Я пытаюсь максимально эффективно преобразовать беззнаковые целочисленные данные в их двоичное представление в памяти.

Я написал четыре шаблонные функции для преобразования целых чисел как в прямой, так и в обратный порядок байтов, две из них используют битовые операции, а две другие используют указатели для копирования данных.

Они проверены как правильные, а также очень эффективные, поскольку я определил, что функции с прямым порядком байтов будут такими же быстрыми, как std::memcpy, но функции с прямым порядком байтов почему-то занимают немного больше времени.

Эти функции:

#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 вместо циклов for?


Добавление constexpr к size_t size = sizeof(T); не привело к компиляции.

Вы не используете пакет параметров нигде в своем расширении, и size не используется constexpr. Но в любом случае это в большинстве случаев бессмысленно, компиляторы прекрасно видят константный ограниченный цикл.

Passer By 25.05.2024 13:40

-> constexpr size_t size = sizeof(T);

Jarod42 25.05.2024 13:46

Кроме того, если вы гонитесь за производительностью, вам не следует передавать std::vector для каждого сериализуемого объекта. Скорее всего, вы просто хотите записать данные в уже существующий буфер.

Passer By 25.05.2024 13:46

SCNR: boost.org/doc/libs/1_85_0/libs/endian/doc/html/endian.html -- Я уверен, что они уже давно об этом подумали.

Christian Stieber 25.05.2024 13:49
((*(dst+N) = *(src+N)) , ...);
Ahmed AEK 25.05.2024 14:03

Обратите также внимание, что ваша реализация предполагает порядок байтов хоста.

Jarod42 25.05.2024 14:16

Я исправил код согласно комментариям, но потом после тестирования обнаружил, что это не ускоряет код, как я предполагал, поэтому я хотел удалить вопрос, но теперь опубликован ответ...

Ξένη Γήινος 25.05.2024 14:21

Не забудьте измерить производительность до и после, с включенной оптимизацией.

HolyBlackCat 25.05.2024 14:40

Если размер constexpr, std::array предпочтительнее std::vector. Тогда можно просто std::bit_cast.

Red.Wave 25.05.2024 15:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У вас есть 2 проблемы:

size не является constexpr, поэтому его нельзя использовать в качестве аргумента шаблона.

-> constexpr size_t size = sizeof(T);

Ваше выражение сгиба не использует какой-либо пакет.

Так что либо

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

Демо

Другие вопросы по теме

В чем разница между использованием концепции напрямую вместо `typename` и использованием ключевого слова `requires`? Или это просто вопрос стиля?
Как реализовать несколько операторов вставки (<<) для класса C++?
Ошибка при изменении порядка операторов с помощью шаблонов в C++
CPreprocess и шаблонизация в C++ для нетипового шаблона
Как интегрировать внешние шаблоны в Laravel + Vite?
Как создать класс шаблона, использующий параметр шаблона нетипового типа, «подружиться» с другим классом шаблона, использующим тот же параметр шаблона нетипового типа?
Как избежать дублирования текста строкового литерала в функциях, которые принимают символы/строки разной ширины?
Как выполнить идеальную пересылку, когда аргумент шаблона явно объявлен
Как реализовать неявное приведение и операторы для класса-оболочки std::variant?
Почему первая функция работает, а вторая нет?