Compartilhar via


Modelos de alias de <ranges>

Um modelo de alias é um alias para outro tipo, o que pode tornar o código mais legível. Por exemplo, o seguinte alias, conditional_t, é um alias para um borrowed_range ou dangling intervalo, dependendo do tipo de range que é passado:

// requires /std:c++20, or later

#include <iostream>
#include <list>
#include <span>
#include <algorithm>
#include <ranges>
#include <type_traits>

using namespace std;

// Define an alias template called my_iterator_t
// If the provided range R is a borrowed_range, then the 
// returned type is iterator_t<R>; otherwise, ranges::dangling
template<ranges::range R>
using my_iterator_t = conditional_t<
    ranges::borrowed_range<R>,
    ranges::iterator_t<R>, ranges::dangling>;

int main()
{
    my_iterator_t<list<int>> aDanglingRange; // list<> isn't a borrowed_range
    constexpr bool same = same_as<
        decltype(aDanglingRange),
        ranges::dangling>; // true

    my_iterator_t<span<int, 5>> anIterator_t; // span<> is a borrowed_range
    constexpr bool same2 = same_as<
        decltype(anIterator_t),
        ranges::iterator_t<span<int, 5>>>; // true

    cout << boolalpha << same << "," << same2; // outputs true, true
}

Para obter mais informações sobre modelos de alias, consulte Aliases e typedefs.

O <algorithm> cabeçalho define os seguintes modelos de alias que determinam os tipos de iteradores e sentinelas para um range:

Modelo de alias Descrição
borrowed_iterator_tC++20 Determine se um iterador retornado para a range se refere a um intervalo cujo tempo de vida terminou.
borrowed_subrange_tC++20 Determine se um subrange for a range retornado se refere a um intervalo cujo tempo de vida terminou.
danglingC++20 Indica que o iterador retornado de um range/subrange sobrevive ao tempo de vida do qual ele range/subrange se refere.
iterator_tC++20 Retorna o tipo de iterador para o intervalo especificado.
range_difference_tC++20 Retorna o tipo de diferença para o iterador do intervalo especificado.
range_reference_tC++20 Retorna o tipo de referência para o iterador do intervalo especificado.
range_rvalue_reference_tC++20 Retorna o tipo de referência rvalue para o iterador do intervalo especificado. Em outras palavras, o tipo de referência rvalue dos elementos do intervalo.
range_size_tC++20 Retorna o tipo usado para relatar o arquivo size.
range_value_tC++20 Retorna o tipo de valor do iterador do intervalo especificado. Ou, em outras palavras, o tipo dos elementos no intervalo.
sentinel_tC++20 Retorna o tipo sentinela para o intervalo especificado.

borrowed_iterator_t

Quando uma função de algoritmo que retorna um iterador é chamada com um argumento rvalue range , o tempo de vida do intervalo pode terminar após a chamada. Isso significa que o iterador retornado pode se referir a elementos cujos tempos de vida terminaram. O uso de um iterador pendente resulta em um comportamento indefinido.

Esse alias de modelo retorna ranges::dangling para indicar que essa é a situação para o argumento de intervalo fornecido ou std::ranges::iterator_t<R> para indicar que é seguro usar o iterador retornado porque o intervalo ao qual ele se refere aos modelos borrowed_range ou ao intervalo foi passado como um lvalue.

template<ranges::range R>
using borrowed_iterator_t = conditional_t<ranges::borrowed_range<R>,
    ranges::iterator_t<R>, ranges::dangling>;

Parâmetros

R
O intervalo a ser testado.

Comentários

O tempo de vida de um intervalo de rvalue pode terminar após uma chamada de função, independentemente de o intervalo ser modelo borrowed_range ou não. Se for um borrowed_range, você poderá continuar a usar os iteradores com um comportamento bem definido, independentemente de quando o tempo de vida do intervalo terminar.

Os casos em que isso não é verdade são, por exemplo, para contêineres como vector ou list porque, quando o tempo de vida do contêiner termina, os iteradores se referem a elementos que foram destruídos.

Você pode continuar a usar os iteradores para um borrowed_range, por exemplo, para um view like iota_view<int>{0, 42} cujos iteradores estão acima do conjunto de valores que não estão sujeitos a serem destruídos porque são gerados sob demanda.

Se uma função de algoritmo for passada, ranges::dangling um intervalo cujos iteradores dependem de seu tempo de vida será retornado em vez de um iterador ou subintervalo, portanto, o uso indevido potencial será detectado em tempo de compilação.

Exemplo: borrowed_iterator_t

O exemplo a seguir mostra como borrowed_iterator_t o detecta um iterador pendente. A função ranges::max_element() usa esse alias de modelo para determinar o tipo de retorno:

// requires /std:c++20, or later

#include <vector>
#include <span>
#include <ranges>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    // Not dangling ------------------

    int a[] = {0,1,2,3};

    // not dangling even though an rvalue because span models ranges::borrowed
    auto result1 = ranges::max_element(span{a});
    cout << boolalpha << ranges::borrowed_range<decltype(span{a})> << endl; // outputs true because the temporary models ranges::borrowed
    cout << same_as<decltype(result1), ranges::dangling> << endl; // outputs false because the result isn't dangling

    vector<int> v{0,1,2,3}; // doesn't model ranges::borrowed
    auto result2 = ranges::max_element(v); // Yet not dangling because passed as an lvalue
    cout << same_as<decltype(result2), ranges::dangling> << endl; // outputs false because the result isn't dangling
    
    // Dangling ------------------

    auto result3 = ranges::max_element(vector{0,1,2,3}); // dangling because vector doesn't model ranges::borrowed and is passed as an rvalue
    cout << same_as<decltype(result3), ranges::dangling>; // outputs true because the result is dangling
}
true
false
false
true

borrowed_subrange_t

Quando uma função de algoritmo que retorna a subrange é chamada com um argumento rvalue range , o tempo de vida do intervalo pode terminar após a chamada. Isso significa que o retorno subrange pode se referir a elementos cujas vidas terminaram. O uso de subrange um pendente resulta em um comportamento indefinido.

Esse alias de modelo retorna ranges::dangling para indicar que essa pode ser a situação para o argumento de intervalo fornecido ou subrange<ranges::iterator_t<R>> para indicar que é seguro usar o subintervalo retornado porque o intervalo cujos elementos ele se refere a modelos borrowed_range ou o intervalo foi passado como um lvalue.

template<ranges::range R>
using borrowed_subrange_t = conditional_t<ranges::borrowed_range<R>,
    ranges::subrange<ranges::iterator_t<R>>, ranges::dangling>;

Parâmetros

R
O intervalo a ser testado.

Comentários

O tempo de vida de um intervalo de rvalue pode terminar após uma chamada de função, independentemente de o intervalo ser modelo borrowed_range ou não. Se for um borrowed_range, você poderá continuar a usar os iteradores com um comportamento bem definido, independentemente de quando o tempo de vida do intervalo terminar.

Os casos em que isso não é verdade são, por exemplo, para contêineres como vector ou list porque, quando o tempo de vida do contêiner termina, os iteradores se referem a elementos que foram destruídos.

Você pode continuar a usar os iteradores para um borrowed_range, por exemplo, para um view like iota_view<int>{0, 42} cujos iteradores estão acima do conjunto de valores que não estão sujeitos a serem destruídos porque são gerados sob demanda.

Se uma função de algoritmo for passada, ranges::dangling um intervalo cujos iteradores dependem de seu tempo de vida será retornado em vez de um subintervalo para que o uso indevido potencial seja detectado em tempo de compilação.

Exemplo: borrowed_subrange_t

O exemplo a seguir mostra como borrowed_subrange_t o detecta um iterador pendente porque equal_range() e max_element usa esse alias de modelo para determinar o tipo de retorno:

// requires /std:c++20, or later

#include <vector>
#include <iostream>
#include <algorithm>
#include <span>
#include <ranges>

int main()
{
    using namespace std;

    // Not dangling ------------------

    vector vec{0, 1, 1, 2};

    auto result1 = ranges::equal_range(span{vec}, 1); // not dangling even though passing as an rvalue because span models borrowed_range
    cout << boolalpha << ranges::borrowed_range<decltype(span{vec})> << endl;  // true because the temporary is a borrowed range
    cout << boolalpha << same_as<decltype(result1), ranges::dangling> << endl; // false because the result isn't dangling

    // result2 isn't dangling even though vec doesn't model ranges::borrowed because it's an lvalue
    auto result2 = ranges::max_element(vec);
    cout << boolalpha << ranges::borrowed_range<decltype(vec)> << endl;  // false because vector isn't a borrowed_range
    cout << boolalpha << same_as<decltype(result2), ranges::dangling> << endl; // false because the result isn't dangling

    // Dangling -----------------------

    // result3 is dangling because the temporary is an rvalue that doesn't model borrowed_range
    auto result3 = ranges::max_element(vector{0,1,1,2});
    cout << boolalpha << same_as<decltype(result3), ranges::dangling> << endl; // true because the result is dangling
}
true
false
false
false
true

dangling

Se uma função de algoritmo que retorna um iterador ou a subrange for chamada com um argumento rvalue range , o tempo de vida do argumento range poderá terminar após a chamada. Isso significa que o iterador retornado ou subrange pode se referir a elementos cujos tempos de vida terminaram. Usar um iterador pendente ou subrange resulta em comportamento indefinido.

Se uma função de algoritmo for passada, ranges::dangling um intervalo cujos iteradores dependem de seu tempo de vida será retornado em vez de um iterador ou subintervalo para que o uso indevido potencial seja detectado em tempo de compilação.

1) constexpr dangling() noexcept = default;
2) template<class... Args>
constexpr dangling(Args&&...) noexcept {}

Parâmetros

Args
Um número variável de não-tiposvoid . Eles não têm efeito. Os argumentos são uma conveniência para que você não precise de caminhos de código diferentes para lidar com a construção do tipo de iterador versus o dangling tipo. Isso é útil quando o valor passado indica que dangling deve ser retornado em vez de um iterador.

Exemplo: dangling

O exemplo a seguir mostra como max_element o detecta um iterador pendente.

// requires /std:c++20, or later

#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>

using namespace std;

int main()
{
    auto result1 = ranges::max_element(vector{1,2,3}); // dangling because vector doesn't model ranges::borrowed and is passed as an rvalue
    cout << boolalpha << same_as<decltype(result1), ranges::dangling> << endl; // outputs true because the result is dangling

    vector<int> v{3,4,5};
    auto result2 = ranges::max_element(v); // Not dangling because passed as an lvalue
    cout << same_as<decltype(result2), ranges::dangling>; // outputs false because the result isn't dangling
}
true
false

iterator_t

Esse alias de modelo retorna o tipo de iterador usado para iterar sobre o tipo de intervalo fornecido.

template<class T>
using iterator_t = decltype(ranges::begin(declval<T&>()));

Parâmetros

T
O tipo de intervalo para o qual obter o tipo de iterador.

Exemplo: iterator_t

O exemplo a seguir mostra como iterator_t pode ser usado para declarar um iterador para um vetor:

// requires /std:c++20, or later

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};

    ranges::iterator_t<decltype(v)> it = v.begin();
    cout << *it << "\n"; // outputs 1
    cout << typeid(it).name(); // outputs class _Vector_iterator<class _Vector_val<struct _Simple_types<int>>>
}
1
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<int> > >

range_difference_t

Retorna o tipo de diferença para o iterador do intervalo especificado.

template<range R>
using range_difference_t = iter_difference_t<iterator_t<R>>;

Parâmetros

R
O intervalo cujo iterador fornecerá o tipo de diferença.

Exemplo: range_difference_t

O exemplo a seguir mostra como range_difference_t é usado para manter a distância entre os elementos em um intervalo:

// requires /std:c++20, or later

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};

    auto findIt = ranges::find(v, 2);
    // type of distance is ptrdiff_t
    ranges::range_difference_t<decltype(v)> distance = ranges::distance(v.begin(), findIt);
    cout << distance << endl; // outputs 1
}
1

range_reference_t

Retorna o tipo de referência para o iterador do intervalo especificado. Em outras palavras, o tipo de referência dos elementos do intervalo.

template <range R>
using range_reference_t = iter_reference_t<ranges::iterator_t<R>>;

Parâmetros

R
O intervalo para o qual o tipo de referência de seu tipo de iterador é retornado.

Exemplo: range_reference_t

O exemplo a seguir mostra range_reference_t a referência ao tipo dos elementos em um intervalo:

// requires /std:c++20, or later

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};

    ranges::range_reference_t<decltype(v)> ref = v[0];

    cout << ref << endl; // outputs 1
    cout << typeid(ref).name() << endl; // outputs int
}
1
int

range_rvalue_reference_t

Retorna o tipo de referência rvalue para o iterador do intervalo especificado. Em outras palavras, o tipo de referência rvalue dos elementos do intervalo.

template <range R>
using range_rvalue_reference_t = iter_reference_t<ranges::iterator_t<R>>;

Parâmetros

R
O intervalo para obter o tipo de referência rvalue para seu tipo de iterador.

Exemplo: range_rvalue_reference_t

O exemplo a seguir mostra range_rvalue_reference_t a referência a um tipo rvalue dos elementos em um intervalo:

// requires /std:c++20, or later

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};

    ranges::range_rvalue_reference_t<decltype(v)> elementRvalueType = v[0] * 10; // elementRvalueType is int&& 

    cout << elementRvalueType << endl; // outputs 10
    cout << typeid(elementRvalueType).name() << endl; // outputs int
}
10
int

range_size_t

Retorna o size tipo da função para o arquivo .sized_range

template <range R>
using range_size_t = iter_reference_t<ranges::iterator_t<R>>;

Parâmetros

R
O intervalo para obter o tipo de sua size função.

Exemplo: range_size_t

O exemplo a seguir mostra range_size_t a referência ao número de elementos em um intervalo:

// requires /std:c++20, or later

#include <vector>
#include <iostream>
#include <ranges>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};

    ranges::range_size_t<decltype(v)> size = v.size();
    cout << size << endl; // outputs 3
    cout << typeid(size).name(); // outputs unsigned __int64
}
3
unsigned __int64

range_value_t

Retorna o tipo de valor do iterador do intervalo especificado. Ou, em outras palavras, o tipo dos elementos no intervalo.

template <ranges::range R>
using range_value_t = iter_value_t<ranges::iterator_t<R>>;

Parâmetros

R
O intervalo para obter o tipo de valor de seu iterador.

Exemplo: range_value_t

O exemplo a seguir mostra como range_value_t se refere ao tipo de elementos em um intervalo:

// requires /std:c++20, or later

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    using namespace std;

    vector<int> v{1,2,3};
    ranges::range_value_t<decltype(v)> elementType = v[2]; // elementType is an int 

    cout << elementType << endl; // outputs 3
    cout << typeid(elementType).name() << endl; // outputs int
}
3
unsigned int

sentinel_t

Retorna o tipo sentinela para o intervalo especificado.

template <range R>
using sentinel_t = decltype(ranges::end(declval<R&>()));

Parâmetros

R
O intervalo para obter o tipo sentinela.

Exemplo: sentinel_t

O exemplo a seguir mostra using sentinel_t para determinar se o tipo de iterador e o tipo sentinela são os mesmos:

// requires /std:c++20, or later

#include <iostream>
#include <list>
#include <ranges>

int main()
{
    using namespace std;

    list myList{1, 2, 3};
    ranges::subrange count = std::views::counted(myList.begin(), myList.size());

    ranges::iterator_t<decltype(count)> first;
    ranges::sentinel_t<decltype(count)> last;

    // The iterator type and the sentinel type of a subrange
    // obtained from views::counted are not the same
    cout << boolalpha << is_same<decltype(first), decltype(last)>::value << endl; // outputs false
    cout << "iter: " << typeid(first).name() << "\n\n end: " << typeid(last).name() << endl;
}
false
iter: class std::counted_iterator<class std::_List_iterator<class std::_List_val<struct std::_List_simple_types<int> > > >

 end: struct std::default_sentinel_t

Confira também

<ranges>
Adaptadores de gama
Ver aulas