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_t C++20 |
Determine se um iterador retornado para a range se refere a um intervalo cujo tempo de vida terminou. |
borrowed_subrange_t C++20 |
Determine se um subrange for a range retornado se refere a um intervalo cujo tempo de vida terminou. |
dangling C++20 |
Indica que o iterador retornado de um range /subrange sobrevive ao tempo de vida do qual ele range /subrange se refere. |
iterator_t C++20 |
Retorna o tipo de iterador para o intervalo especificado. |
range_difference_t C++20 |
Retorna o tipo de diferença para o iterador do intervalo especificado. |
range_reference_t C++20 |
Retorna o tipo de referência para o iterador do intervalo especificado. |
range_rvalue_reference_t C++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_t C++20 |
Retorna o tipo usado para relatar o arquivo size . |
range_value_t C++20 |
Retorna o tipo de valor do iterador do intervalo especificado. Ou, em outras palavras, o tipo dos elementos no intervalo. |
sentinel_t C++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