Compartilhar via


Classes de exibição de <ranges>

Um modo de exibição é um intervalo leve que se refere a elementos que ele não possui (exceto owning_view). Uma exibição geralmente é baseada em outro intervalo e fornece uma maneira diferente de vê-la, seja transformando-a ou filtrando-a. Por exemplo, std::views::filter é um modo de exibição que usa os critérios especificados para selecionar elementos de outro intervalo.

Quando você acessa os elementos em uma exibição, isso é feito "preguiçosamente" para que o trabalho seja feito apenas quando você obtém um elemento. Isso torna possível combinar, ou compor, visualizações sem uma penalidade de desempenho.

Por exemplo, você pode criar um modo de exibição que forneça apenas os elementos pares de um intervalo e, em seguida, transformá-los em quadratura deles. O trabalho para fazer a filtragem e a transformação é feito apenas para os elementos que você acessa e somente quando você os acessa.

Uma exibição pode ser copiada, atribuída e destruída em tempo constante, não importa quantos elementos ela contenha. Isso ocorre porque um modo de exibição não possui os elementos aos quais se refere, portanto, não precisa fazer uma cópia. É por isso que você pode compor exibições sem uma penalidade de desempenho.

Normalmente, você cria um modo de exibição usando um adaptador de intervalo. Os adaptadores de intervalo são a maneira pretendida de criar um modo de exibição, são mais fáceis de usar do que instanciar as classes de exibição diretamente e, às vezes, são mais eficientes do que instanciar as classes de exibição diretamente. As classes de exibição são expostas diretamente caso você precise criar seu próprio tipo de exibição personalizado com base em um tipo de exibição existente.

Aqui está um breve exemplo de criação de uma exibição dos quadrados dos elementos que são divisíveis por três em um vetor:

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> input =  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto divisible_by_three = [](const int n) {return n % 3 == 0;};
    auto square = [](const int n) {return n * n;};

    auto x = input
             | std::views::filter(divisible_by_three)
             | std::views::transform(square);

    for (int i : x)
    {
        std::cout << i << ' '; // 0 9 36 81
    }
}
0 9 36 81

Usar um modo de exibição depois que o intervalo no qual ele se baseia é modificado pode levar a um comportamento indefinido. Por exemplo, um baseado em um reverse_view vetor não deve ser reutilizado se você adicionar ou remover elementos do vetor subjacente. A modificação do vetor subjacente invalida o iterador do contêiner - incluindo a cópia do end iterador que a exibição pode ter feito.

Como os modos de exibição são baratos de criar, você geralmente deve recriar um modo de exibição se modificar o intervalo subjacente. O exemplo a seguir demonstra como armazenar um pipeline de exibição em uma variável para que você possa reutilizá-lo.

// requires /std:c++20, or later
#include <iostream>
#include <ranges>
#include <vector>
#include <list>
#include <string_view>
#include <algorithm>

template<typename rangeType>
void show(std::string_view msg, rangeType r)
{
    std::cout << msg;
    std::ranges::for_each(r,
        [](auto e)
        {
            std::cout << e << ' ';
        });
    std::cout << '\n';
}

int main()
{
    std::vector v{ 1, 2, 3, 4 };
    show("v: ", v);

    // You can save a view pipeline
    auto rev3 = std::views::take(3) | std::views::reverse;

    show("v | rev3: ", v | rev3); // 3 2 1

    v.insert(v.begin(), 0); // v = 0 1 2 3 4
    show("v: ", v);

    // Because modifying the vector invalidates its iterators, rebuild the view.
    // We are reusing the view pipeline we saved earlier
    show("v | rev3(v): ", rev3(v));
}
v: 1 2 3 4
v | rev3: 3 2 1
v: 0 1 2 3 4
v | rev3(v): 2 1 0

As classes de exibição a std::ranges seguir são definidas no namespace.

Exibir Descrição
basic_istream_viewC++20 Uma exibição de elementos sucessivos de um fluxo de entrada. As especializações incluem istream_view e wistream_view.
common_viewC++20 Adapta um modo de exibição que tem diferentes tipos de iterador/sentinela em um modo de exibição com os mesmos tipos de iterador/sentinela.
drop_viewC++20 Criado a partir de outro modo de exibição, ignorando os primeiros count elementos.
drop_while_viewC++20 Criado a partir de outro modo de exibição, ignorando elementos principais enquanto um predicado se mantém.
elements_viewC++20 Uma exibição sobre o índice selecionado em cada valor semelhante a tupla em uma coleção. Por exemplo, dado um intervalo de valores, crie um modo de exibição que consiste em todos os string elementos de std::tuple<string, int> cada tupla.
empty_viewC++20 Uma vista sem elementos.
filter_viewC++20 Filtra elementos de um intervalo que não correspondem a um predicado.
iota_viewC++20 Um modo de exibição gerado que contém uma sequência de valores incrementais.
join_viewC++20 Combina todos os elementos de vários intervalos em uma única exibição.
keys_viewC++20 Uma exibição sobre o primeiro índice em cada valor semelhante a uma tupla em uma coleção. Por exemplo, dado um intervalo de valores, crie um modo de exibição que consiste nos string elementos de std::tuple<string, int> cada tupla.
lazy_split_viewC++20 Divide uma exibição em subintervalos com base em um delimitador.
owning_viewC++20 Apropria-se dos elementos de outro intervalo.
ref_viewC++20 Um modo de exibição que faz referência aos elementos que pertencem a outro intervalo.
reverse_viewC++20 Apresenta os elementos de um intervalo em ordem inversa.
single_viewC++20 Um modo de exibição que contém apenas um elemento.
split_viewC++20 Divide uma exibição em subintervalos com base em um delimitador.
subrangeC++20 Uma exibição de parte dos elementos de um intervalo, conforme definido por um iterador inicial e uma sentinela.
take_viewC++20 Contém o número especificado de elementos retirados da frente de um intervalo.
take_while_viewC++20 Contém os elementos principais de um intervalo que correspondem ao predicado fornecido.
transform_viewC++20 Uma exibição de uma sequência subjacente após uma função de transformação é aplicada a cada elemento.
values_viewC++20 Uma exibição sobre o segundo índice em cada valor semelhante a uma tupla em uma coleção. Por exemplo, dado um intervalo de valores, crie um modo de exibição que consiste nos int elementos de std::tuple<string, int> cada tupla.

Muitas dessas classes têm adaptadores de intervalo correspondentes no std:views namespace que cria instâncias delas. Prefira usar um adaptador para criar um modo de exibição em vez de criar classes de exibição diretamente. Os adaptadores de gama são a forma pretendida de criar vistas, são mais fáceis de utilizar e, em alguns casos, são mais eficientes.

Exibir características das classes

Cada tópico de classe de exibição tem uma seção Características após a seção de sintaxe. A seção Características tem as seguintes entradas:

  • Adaptador de intervalo: um link para o adaptador de intervalo que cria a exibição. Normalmente, você usa um adaptador de intervalo para criar um modo de exibição em vez de criar uma classe de exibição diretamente, por isso ele é listado aqui por conveniência.

  • Intervalo subjacente: as exibições têm requisitos de iterador diferentes para o tipo de intervalo subjacente que podem usar. Consulte hierarquia de iteradores de intervalos para obter mais informações sobre os tipos de iteradores .

  • Exibir categoria do iterador: A categoria do iterador do modo de exibição. Quando um modo de exibição adapta um intervalo, o tipo de iterador para o modo de exibição é normalmente o mesmo que o tipo de iterador do intervalo subjacente. No entanto, pode ser diferente para algumas visões. Por exemplo, tem um , reverse_view mesmo que o intervalo subjacente tenha um random_access_iteratorbidirectional_iterator.

  • Tipo de elemento: o tipo dos elementos que o iterador do modo de exibição retorna.

  • Tamanho: se o modo de exibição pode retornar o número de elementos aos quais ele se refere. Nem todas as visões podem.

  • Intervalo comum: especifica se o modo de exibição é um common_range, o que significa que os tipos iterador inicial e sentinela são os mesmos. Intervalos comuns são úteis para código de pré-intervalo que funciona com pares de iteradores. Um exemplo são construtores de pares iteradores para um contêiner de sequência, como vector(ranges::begin(x), ranges::end(x)).

  • Intervalo emprestado: especifica se o modo de exibição é um intervalo emprestado. borrowed_range<T> significa que você pode usar iteradores para T depois T é destruído.

    Nenhum contêiner padrão é um intervalo emprestado, porque destruir o contêiner libera os elementos e invalida quaisquer iteradores. Nesse caso, dizemos que os iteradores são deixados "pendurados" após a destruição.

    Por exemplo, std::ranges::find() normalmente retorna um iterador para o elemento encontrado no argumento range. Se o argumento range for um contêiner temporário (rvalue), é um erro armazenar o iterador retornado e usá-lo mais tarde porque ele está "pendurado".

    Os algoritmos de intervalo que retornam iteradores (ou subintervalos) o fazem somente quando seus argumentos são lvalues (não temporários) ou intervalos emprestados. Caso contrário, eles retornam um objeto, que fornece uma dica em mensagens de erro sobre o que deu errado se você tentou usá-lo como um std::dangling iterador.

  • É const iterável: indica se você pode iterar sobre uma const instância do modo de exibição. Nem todos os const modos de exibição podem ser iterados. Se um modo de exibição não for iterável, você não const poderá iterá-lo for (const auto& element : as_const(theView)) ou passá-lo para uma função que faça uma const referência ao modo de exibição e, em seguida, tente iterar sobre ele.

Hierarquia do iterador de intervalos

Na seção Características de cada tópico de classe de exibição, a categoria iterador em Intervalo subjacente e Categoria iterador Exibir refere-se ao tipo de iterador que o intervalo/modo de exibição suporta. Existem seis categorias de iteradores de intervalos, que são identificados pelos conceitos do C++20. A hierarquia dos iteradores de intervalo, em ordem crescente de capacidade, é:

Conceito de iterador de alcance Descrição
output_range Somente gravação, só avança; Passe único.
input_range Somente leitura, só avança; Passe único.
forward_range Só avança; multi-passagem.
bidirectional_range Pode mover-se para a frente e para trás; multi-passagem.
random_access_range Pode acessar o acervo com um índice; multi-passagem.
contiguous_range Pode acessar a coleção com um índice, e os elementos são armazenados de forma contígua na memória.

De um modo geral, um iterador tem a capacidade dos iteradores que o precedem na tabela. Por exemplo, tem as capacidades de forward_range, bidirectional_range mas não vice-versa. Exceto input_range, que não tem a capacidade de output_range porque você não pode gravar em um input_rangearquivo .

A instrução "requer input_range ou superior" significa que a exibição pode ser usada com um input_range, , , , ou iterador, forward_rangerandom_access_rangebidirectional_rangecontiguous_range porque todos eles são tão capazes quanto .input_range

A hierarquia do iterador de intervalos está diretamente relacionada à hierarquia do iterador. Para obter mais informações, consulte Conceitos do iterador.

Confira também

<ranges>
Adaptadores de gama