如何重用 C++23 `std::generator` 实例作为多个范围表达式中的范围?

问题描述 投票:0回答:1

我正在尝试学习 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>’)

达到预期效果的正确方法(如果有)是什么?

c++ c++20 std-ranges c++23
1个回答
0
投票

你不知道。

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; }
}
© www.soinside.com 2019 - 2024. All rights reserved.