Поделиться через


<ranges> Шаблоны псевдонимов

Шаблон псевдонима — это псевдоним другого типа, который может сделать код более читаемым. Например, следующий псевдоним , является псевдонимом conditional_tдля любого borrowed_range или dangling диапазона в зависимости от типа range переданного в:

// 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
}

Дополнительные сведения о шаблонах псевдонимов см. в разделе "Псевдонимы" и "Typedefs".

Заголовок <algorithm> определяет следующие шаблоны псевдонимов, определяющие типы итераторов и sentinels для range:

Шаблон псевдонима Description
borrowed_iterator_tC++20 Определите, возвращается ли итератор для range диапазона, время существования которого завершено.
borrowed_subrange_tC++20 Определите, возвращается ли возвращаемый subrange диапазон range , время существования которого завершилось.
danglingC++20 Указывает, что возвращаемый итератор извеченного времени существования/subrange rangeссылки на него.range/subrange
iterator_tC++20 Возвращает тип итератора для указанного диапазона.
range_difference_tC++20 Возвращает тип разницы для итератора указанного диапазона.
range_reference_tC++20 Возвращает ссылочный тип для итератора указанного диапазона.
range_rvalue_reference_tC++20 Возвращает ссылочный тип rvalue для итератора указанного диапазона. Другими словами, ссылочный тип rvalue элементов диапазона.
range_size_tC++20 Возвращает тип, используемый для отправки отчета о заданном диапазоне size.
range_value_tC++20 Возвращает тип значения итератора указанного диапазона. Или другими словами, тип элементов в диапазоне.
sentinel_tC++20 Возвращает тип sentinel для указанного диапазона.

borrowed_iterator_t

Если функция алгоритма, возвращающая итератор, вызывается с аргументом rvalue range , время существования диапазона может завершиться после вызова. Это означает, что возвращаемый итератор может ссылаться на элементы, время существования которых завершилось. Использование дальнего итератора приводит к неопределенному поведению.

Этот псевдоним шаблона возвращается ranges::dangling , чтобы указать, что это ситуация для заданного аргумента диапазона или std::ranges::iterator_t<R> чтобы указать, что он безопасно использовать возвращаемый итератор, так как диапазон, который он относится к моделям borrowed_range или диапазон был передан как lvalue.

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

Параметры

R
Диапазон для тестирования.

Замечания

Время существования диапазона rvalue может завершиться после вызова функции, независимо от того borrowed_range , модели диапазона или нет. Если это borrowed_rangeтак, вы можете продолжать использовать итераторы с хорошо определенным поведением независимо от того, когда время существования диапазона заканчивается.

В случаях, когда это не так, например для контейнеров, таких vector как или list из-за окончания времени существования контейнера, итераторы будут ссылаться на элементы, которые были уничтожены.

Вы можете продолжать использовать итераторы для borrowed_rangeнапример, например, например, для view iota_view<int>{0, 42} того, чьи итераторы имеют набор значений, которые не подвергаются уничтожению, так как они создаются по требованию.

Если функция алгоритма передает диапазон, итераторы которого зависят от его времени существования, ranges::dangling возвращается вместо итератора или подранга, поэтому потенциальное неправильное использование обнаруживается во время компиляции.

Пример: borrowed_iterator_t

В следующем примере показано, как borrowed_iterator_t обнаружить итератор дальнего итератора. ranges::max_element() Функция использует этот псевдоним шаблона для определения типа возвращаемого значения:

// 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

Когда функция алгоритма, возвращающая subrange вызов с аргументом rvalue range , время существования диапазона может завершиться после вызова. Это означает, что возвращаемый subrange объект может ссылаться на элементы, время существования которых завершилось. Использование дальнего subrange поведения приводит к неопределенному поведению.

Этот псевдоним шаблона либо возвращается ranges::dangling , чтобы указать, что это может быть ситуация для заданного аргумента диапазона, либо subrange<ranges::iterator_t<R>> чтобы указать, что он безопасно использовать возвращаемый подранг, так как либо диапазон, элементы которого относятся к моделям borrowed_range , либо диапазон был передан как lvalue.

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

Параметры

R
Диапазон для тестирования.

Замечания

Время существования диапазона rvalue может завершиться после вызова функции, независимо от того borrowed_range , модели диапазона или нет. Если это borrowed_rangeтак, вы можете продолжать использовать итераторы с хорошо определенным поведением независимо от того, когда время существования диапазона заканчивается.

В случаях, когда это не так, например для контейнеров, таких vector как или list из-за окончания времени существования контейнера, итераторы будут ссылаться на элементы, которые были уничтожены.

Вы можете продолжать использовать итераторы для borrowed_rangeнапример, например, например, для view iota_view<int>{0, 42} того, чьи итераторы имеют набор значений, которые не подвергаются уничтожению, так как они создаются по требованию.

Если функция алгоритма передает диапазон, итераторы которого зависят от его времени существования, возвращается вместо подранга, ranges::dangling чтобы потенциальное неправильное использование было обнаружено во время компиляции.

Пример: borrowed_subrange_t

В следующем примере показано, как определить деангистрирующий итератор, так как borrowed_subrange_t equal_range() и max_element использовать этот псевдоним шаблона для определения типа возвращаемого значения:

// 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

Если функция алгоритма, возвращающая итератор или subrange вызывается с аргументом rvalue range , время существования аргумента диапазона может завершиться после вызова. Это означает, что возвращаемый итератор или subrange может ссылаться на элементы, время существования которых завершилось. Использование итератора или subrange неопределенного поведения.

Если функция алгоритма передает диапазон, итератор которого зависит от его времени существования, возвращается вместо итератора или подранга, ranges::dangling чтобы потенциальное неправильное использование было обнаружено во время компиляции.

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

Параметры

Args
Переменное число нетиповvoid . Они не имеют никакого эффекта. Аргументы являются удобством, поэтому для обработки создания типа dangling итератора не требуется разные пути кода. Это полезно, если переданное значение указывает, что dangling следует возвращать вместо итератора.

Пример: dangling

В следующем примере показано, как max_element обнаружить итератор дальнего итератора.

// 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

Этот псевдоним шаблона возвращает тип итератора, используемый для итерации по указанному типу диапазона.

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

Параметры

T
Тип диапазона для получения типа итератора.

Пример: iterator_t

В следующем примере показано, как iterator_t можно объявить итератор для вектора:

// 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

Возвращает тип разницы для итератора указанного диапазона.

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

Параметры

R
Диапазон, итератор которого предоставит тип разницы.

Пример: range_difference_t

В следующем примере показано, как range_difference_t использовать для хранения расстояния между элементами в диапазоне:

// 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

Возвращает ссылочный тип для итератора указанного диапазона. Другими словами, ссылочный тип элементов диапазона.

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

Параметры

R
Диапазон, для которого возвращается ссылочный тип своего итератора.

Пример: range_reference_t

В следующем примере показано range_reference_t , как ссылаться на тип элементов в диапазоне:

// 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

Возвращает ссылочный тип rvalue для итератора указанного диапазона. Другими словами, ссылочный тип rvalue элементов диапазона.

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

Параметры

R
Диапазон для получения ссылочного типа rvalue к типу итератора.

Пример: range_rvalue_reference_t

В следующем примере показано range_rvalue_reference_t , как ссылаться на тип rvalue элементов в диапазоне:

// 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

Возвращает тип size функции для указанного sized_range.

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

Параметры

R
Диапазон для получения типа его size функции.

Пример: range_size_t

В следующем примере показано range_size_t число элементов в диапазоне:

// 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

Возвращает тип значения итератора указанного диапазона. Или другими словами, тип элементов в диапазоне.

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

Параметры

R
Диапазон для получения типа значения своего итератора.

Пример: range_value_t

В следующем примере показано, как range_value_t относится к типу элементов в диапазоне:

// 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

Возвращает тип sentinel для указанного диапазона.

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

Параметры

R
Диапазон для получения типа sentinel для.

Пример: sentinel_t

В следующем примере показано использование для sentinel_t определения того, совпадают ли тип итератора и тип sentinel:

// 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

См. также

<ranges>
Адаптеры диапазона
Просмотр классов