我正在尝试学习 C++ 范围。据我所知,创建生成自定义序列的范围视图对象的最简单(也是唯一缺少实现自定义范围视图类)的方法是使用 C++23'
std::generate()
:
std::generator<char> letters_gen(char start)
{
for (;;) co_yield start++;
}
如何在涉及范围运算的多个表达式中使用
std::generator
对象(通过调用 letters_gen()
创建)?例如。如果我想将 10 个字母收集到一个向量中,然后再收集 15 个字母到另一个向量中:
void main()
{
auto letters = letters_gen('a');
auto x = letters | std::views::take(10) | std::ranges::to<std::vector>();
auto y = letters | std::views::take(15) | std::ranges::to<std::vector>();
}
这无法编译:
main.cc:150:26: error: no match for ‘operator|’ (operand types are ‘std::generator<char>’ and ‘std::ranges::views::__adaptor::_Partial<std::ranges::views::_Take, int>’)
达到预期效果的正确方法(如果有)是什么?
你不知道。
A
generator
是一个输入范围,只能使用一次。该库寻求防止滥用的方法之一是使其只能移动而不是可复制 - 因此有人抱怨试图复制它(范围编译错误是众所周知的无用)。即使在范围内调用 begin()
两次也是未定义的行为。
我认为在图书馆内确实没有一个很好的方法来做到这一点。您可以尝试通过执行类似的操作来解决复制问题(这还确保两种算法都使用相同的生成器):
auto x = ranges::ref_view(letters) | views::take(10) | ranges::to<vector>();
auto y = ranges::ref_view(letters) | views::take(15) | ranges::to<vector>();
但这会给你一个令人惊讶的结果,
x
包含从a
到j
的字母,但y
包含l
到z
而不是k
到y
,因为take
与输入范围交互的方式(请参阅 my CppNow talk)。
你必须手写更多的东西:
vector<char> x;
for (size_t count = 0; char c : letters) {
x.push_back(c);
if (++count == 10) { break; }
}
vector<char> y;
for (size_t count = 0; char c : letters) {
y.push_back(c);
if (++count == 15) { break; }
}