Estou tentando aprender intervalos em C++. Até onde posso ver, a maneira mais simples (e a única, além de implementar uma classe de visualização de intervalo personalizada) de criar um objeto de visualização de intervalo que gere uma sequência personalizada é usar C++23' std::generator<>
:
std::generator<char> letters_gen(char start)
{
for (;;) co_yield start++;
}
Como eu uso um std::generator
objeto (como criado ao invocar letters_gen()
) em múltiplas expressões envolvendo operações de intervalo? Por exemplo, se eu quiser coletar 10 letras em um vetor e, então, mais 15 letras em outro vetor:
int 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>();
}
Isto não compila:
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>’)
Qual é a maneira correta, se houver, de obter o efeito desejado?
Você não.
A
generator
é um intervalo de entrada, você só pode usá-lo uma vez. Uma das maneiras que a biblioteca busca evitar o uso indevido é torná-lo somente para movimentação em vez de copiável - daí a reclamação sobre tentar copiá-lo (erros de compilação de intervalos são notoriamente inúteis). É um comportamento indefinido até mesmo chamarbegin()
duas vezes no intervalo.Não há realmente uma boa maneira de fazer isso dentro da biblioteca, eu acho. Você pode tentar contornar o problema de cópia fazendo algo assim (o que adicionalmente garante que ambos os algoritmos usem o mesmo gerador):
Esse é um comportamento indefinido, mas mesmo deixando isso de lado, você obterá um resultado surpreendente que
x
contém as letras dea
thruj
conforme desejado, masy
contéml
thruz
em vez dek
thruy
devido à maneira comotake
interage com os intervalos de entrada (veja minha palestra sobre CppNow ).Você teria que escrever algo mais à mão:
À excelente resposta de Barry, gostaria de acrescentar o seguinte. Nem tudo é tão pessimista. Sim, não poderemos usar views neste caso, mas podemos usar algoritmos – std::copy_n e std::ranges::copy_n:
ou: