C ++: попытка устранить необработанный цикл с помощью эквивалентного алгоритма STL - PullRequest
0 голосов
/ 11 октября 2018

Я пытаюсь модернизировать некоторый код 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>, каждый элемент которого содержит содержимое двух HexChars, один в старших 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 ]

0 голосов
/ 12 октября 2018

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

0 голосов
/ 11 октября 2018

При 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]));
           });
}

Демо

...