我正在尝试使一些C++代码现代化,遵守核心准则和 ++11 后的建议。我在这里讨论的具体准则是使用<algorithm>
工具代替原始循环,在序列中应用静态操作以生成新序列。
第一个例子说明了成功(正如我在此上下文中定义的那样(。std::byte
的两个输入向量进入,一个出来,表示每个输入向量的成对按位异或,使输入向量保持不变。本着这个问题的精神,其功能是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 lengthn");
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
(每个字符最终传达 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;
}
使用 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]));
});
}
演示
没有<algorithm>
允许使用非专用迭代器通过非连续输入消耗进行转换。除了专门的迭代器之外,还有第三方,并且(希望(很快就会成为呈现核心 STL 的标准替代方案/增强功能,例如 ranges(range repository(。有关范围的工作示例,请参阅用户@Jarod42的答案。