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