C++: попытка устранить необработанный цикл с помощью эквивалентного алгоритма STL

Я пытаюсь модернизировать некоторый код C++, придерживаясь основных рекомендаций и рекомендаций после ++11. Конкретное руководство, к которому я обращаюсь, это использовать <algorithm> средства вместо сырых циклов, применяющих статические операции в последовательности с целью создания новой последовательности.

Этот первый пример иллюстрирует успех (как я определяю его в этом контексте). Два входных вектора std::byte входит, и один выходит, представляя попарно побитовое XOR каждого входного вектора, оставляя входные векторы неизмененными. Функция в духе этого вопроса std::transform.

vector<byte> XORSmash(const vector<byte>& first, const vector<byte>& second)
{
    if (first.size() != second.size())
        throw std::invalid_argument("XORSMASH: input vectors were not of equal length\n");

    vector<byte> convolution; convolution.reserve(first.size());

    transform(first.cbegin(), first.cend(), second.cbegin(), back_inserter(convolution),
        [](const byte byte1, const byte byte2) {return byte1 ^ byte2;} );

    return convolution;
}

Тем не менее, есть еще одна функция, для которой у меня возникают проблемы при разработке решения без петель, которое не хуже, чем у цикла. Эта функция принимает в string HexChars(каждый из которых в конечном итоге передает 4 бита значения), и генерирует vector<byte>, каждый элемент которого содержит содержимое двух шестнадцатеричных символов, один в старших 4 битах, один в младших. Что за CharToHexByte функция точно не уместна (я включу, если это станет необходимым), просто она принимает совместимый шестнадцатеричный символ и возвращает std::byte, с числовым значением шестнадцатеричного символа, то есть 0-15, загружая только 4 бита. Проблема заключается в том, что во входной строке есть пары шестнадцатеричных символов (каждый из которых имеет значение), каждая из которых объединяется в один шестнадцатеричный байт. Я не могу использовать std::transformНасколько мне известно, поскольку входные итераторы должны были бы прыгать на 2 (2 * sizeof(char)//aka container_const_iterator += 2 in this case) каждую итерацию, чтобы извлечь следующую пару символов во входной строке.

TLDR: существует ли алгоритм ic для реализации следующей функции без for цикл, который не дороже / многословнее, чем решение ниже?

vector<byte> UnifyHexNibbles(const string& hexStr)
{
    if (hexStr.size() % 2)
        throw std::invalid_argument("UnfyHxNbl: Input String Indivisible by 8bits. Pad if applicable.\n");

    vector<byte> hexBytes; hexBytes.reserve(hexStr.size() >> 1);
    //can I be eliminated elegantly?
    for (size_t left(0), right(1); right < hexStr.size(); left += 2, right += 2)
        hexBytes.push_back( CharToHexByte(hexStr[left]) << 4 | CharToHexByte(hexStr[right]) );

    return hexBytes;
}

2 ответа

Решение

Здесь нет <algorithm> это позволяет осуществлять преобразование через непоследовательное потребление ресурсов с использованием неспециализированных итераторов. Помимо специализации итератора, существуют сторонние, и (мы надеемся), скоро появятся стандартные альтернативы / усовершенствования для представления ядра STL, такие как диапазоны ( репозиторий диапазонов). См. Ответ пользователя @Jarod42 для рабочего примера с диапазонами.

С range-v3 это было бы

std::vector<std::byte>
UnifyHexNibbles(const std::string& hexStr)
{
    if (hexStr.size() % 2)
        throw std::invalid_argument("size indivisible by 2.");


    return hexStr
        | ranges::view::chunk(2)
        | ranges::view::transform([](const auto& r)
           {
              return std::byte(CharToHexByte(r[0]) << 4 | CharToHexByte(r[1]));
           });
}

демонстрация

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