<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>
定义以下别名模板,用于确定 range
的迭代器和 sentinels 的类型:
别名模板 | 说明 |
---|---|
borrowed_iterator_t C++20 |
确定为 range 返回的迭代器是否引用生存期已结束的范围。 |
borrowed_subrange_t C++20 |
确定为 range 返回的 subrange 是否是指生存期已结束的范围。 |
dangling C++20 |
指示返回的 range /subrange 迭代器大于所引用 range /subrange 的生存期。 |
iterator_t C++20 |
返回指定范围的迭代器类型。 |
range_difference_t C++20 |
返回指定范围的迭代器的差异类型。 |
range_reference_t C++20 |
返回指定范围的迭代器的引用类型。 |
range_rvalue_reference_t C++20 |
返回指定范围的迭代器的 rvalue 引用类型。 换句话说,范围元素的 rvalue 引用类型。 |
range_size_t C++20 |
返回用于报告指定范围的 size 的类型。 |
range_value_t C++20 |
返回指定范围的迭代器的值类型。 或者换句话说,范围中元素的类型。 |
sentinel_t C++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
,则无论范围的生存期何时结束,都可以继续使用具有明确定义的行为的迭代器。
例如,对于容器(如 vector
或 list
),情况则有所不同,因为容器的生存期结束时,迭代器将引用已销毁的元素。
可以继续对 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
,则无论范围的生存期何时结束,都可以继续使用具有明确定义的行为的迭代器。
例如,对于容器(如 vector
或 list
),情况则有所不同,因为容器的生存期结束时,迭代器将引用已销毁的元素。
可以继续对 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_range
的 size
函数的类型。
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