<ranges> 别名模板

别名模板是另一种类型的别名,可以使代码更容易读取。 例如,以下别名 (conditional_t) 是 borrowed_rangedangling 范围的别名,具体取决于传入的 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> 定义以下别名模板,用于确定 range 的迭代器和 sentinels 的类型:

别名模板 说明
borrowed_iterator_tC++20 确定为 range 返回的迭代器是否引用生存期已结束的范围。
borrowed_subrange_tC++20 确定为 range 返回的 subrange 是否是指生存期已结束的范围。
danglingC++20 指示返回的 range/subrange 迭代器大于所引用 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
要测试的范围。

备注

值范围的生存期可以在函数调用后结束,无论范围是否遵循 borrowed_range 模型。 如果是 borrowed_range,则无论范围的生存期何时结束,都可以继续使用具有明确定义的行为的迭代器。

例如,对于容器(如 vectorlist),情况则有所不同,因为容器的生存期结束时,迭代器将引用已销毁的元素。

可以继续对 borrowed_range(例如 iota_view<int>{0, 42} 之类的 view)使用迭代器,它们的迭代器基于一组值,这些值不会被销毁,因为它们是按需生成的。

如果算法函数传递的迭代器依赖于其生存期的范围,则会返回 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

当使用 rvalue range 自变量调用返回 subrange 的算法函数时,范围的生存期可能会在调用后结束。 这意味着返回的 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
要测试的范围。

备注

值范围的生存期可以在函数调用后结束,无论范围是否遵循 borrowed_range 模型。 如果是 borrowed_range,则无论范围的生存期何时结束,都可以继续使用具有明确定义的行为的迭代器。

例如,对于容器(如 vectorlist),情况则有所不同,因为容器的生存期结束时,迭代器将引用已销毁的元素。

可以继续对 borrowed_range(例如 iota_view<int>{0, 42} 之类的 view)使用迭代器,它们的迭代器基于一组值,这些值不会被销毁,因为它们是按需生成的。

如果算法函数传递的迭代器依赖于其生存期的范围,则会返回 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

如果使用 rvalue range 自变量调用返回迭代器或 subrange 的算法函数,范围自变量的生存期可能会在调用后结束。 这意味着返回的迭代器或 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

返回指定 sized_rangesize 函数的类型。

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>
范围适配器
视图类