?(end、size 等也一样)两者似乎工作相同:#include <iostream>#include <vector>#include <array>#include <ranges>template<std::ranges::range R>void printInfo(const R &range){ std::cout << (std::ranges::begin(range) == std::begin(range));}template<class T>struct X{ std::vector<T> v; auto begin() const { return v.begin(); } auto end() const { return v.end(); }};int main(){ printInfo(std::vector{1, 2, 3, 4}); printInfo(std::array{1, 2, 3, 4}); printInfo(X<int>{{1, 2, 3, 4}}); int oldSchool[]{1, 2, 3, 4}; printInfo(oldSchool);}按预期编译并打印 1111.ranges::begin 是否会使 std::begin 过时?还是两者有不同的用例?Does ranges::begin make std::begin obsolete? Or do the two have different use-cases?推荐答案有一些区别.首先,ranges::begin(x) 适用于所有范围,而 std::begin(x) 不适用.后者不会对 begin 进行 ADL 查找,因此指定的范围如下:First, ranges::begin(x) works on all ranges while std::begin(x) does not. The latter will not do ADL lookup on begin, so ranges specified like:struct R { ...};auto begin(R const&);auto end(R const&);行不通,这就是为什么你必须写这样的东西:won't work, which is why you have to write something like:using std::begin, std::end;auto it = begin(r);你不必用 ranges::begin 做两步.其次,ranges::begin(x) 更安全一些.Ranges 引入了这个借用范围的概念,这是一个可以安全保留其迭代器的范围.vector 例如不是一个借用的范围 - 因为一旦 vector 死亡,数据就会死亡.ranges::begin 防止这种情况:Second, ranges::begin(x) is a little safer. Ranges introduces this notion of a borrowed range, which is a range whose iterators that you can hold onto safely. vector<int> for instance is not a borrowed range - since once the vector dies the data dies. ranges::begin guards against that:auto get_data() -> std::vector<int>;auto a = std::begin(get_data()); // ok, but now we have a dangling iteratorauto b = ranges::begin(get_data()); // ill-formed第三,ranges::begin 和 ranges::end 有额外的类型检查.ranges::begin(r) 需要 r.begin() 或 begin(r) 的结果来建模 input_or_output_iterator.ranges::end(r) 要求 ranges::begin(r) 有效并且需要 r.end() 或 >end(r) 对 sentinel_for 进行建模.也就是说 - 我们从 begin 和 end 得到的实际上是一个范围.Third, ranges::begin and ranges::end have extra type checks. ranges::begin(r) requires the result of either r.begin() or begin(r) to model input_or_output_iterator. ranges::end(r) requires ranges::begin(r) to be valid and requires either r.end() or end(r) to model sentinel_for<decltype(ranges::begin(r))>. That is - that whatever we get from begin and end is actually a range.这意味着,例如:struct X { int begin() const { return 42; }};X x;auto a = std::begin(x); // ok, a == 42auto b = ranges::begin(x); // ill-formed, int is not an iterator虽然更烦人的是你有一个迭代器类型,它可能是可增加的、可取消引用的、可比较的等等......但没有默认的构造函数.这不符合 C++20 的 input_or_output_iterator 所以 ranges::begin 会失败.Although more annoyingly is a case where you have an iterator type that might be incrementable, dereferenceable, comparable, etc... but fail to have a default constructor. That does not meet the requirements of C++20's input_or_output_iterator so ranges::begin will fail.四、ranges::begin是一个函数对象,而std::begin是一组重载的函数模板:Fourth, ranges::begin is a function object, while std::begin is a set of overloaded function templates:auto f = ranges::begin; // okauto g = std::begin; // error: which std::begin did you want?第五,一些范围自定义点对象除了只调用该名称的函数外,还有其他回退行为.std::size(r) 总是调用一个名为 size 的函数(除非 r 是一个原始数组).std::empty(r) 总是调用一个名为 empty 的函数(除非 r 是一个原始数组,在这种情况下它只是 false,或者 r 是一个 initializer_list,在这种情况下 r.size() == 0).但是 ranges::size 在某些情况下可以 a> 执行 ranges::end(r) - Ranges::begin(r)(如果 size(r) 和 r.size() 不存在)就像 ranges::empty 可以 在某些情况下要么做 ranges::size(r) == 0 或 ranges::begin(r) == 范围::end(r).Fifth, some of the ranges customization point objects have other fallback behavior besides just calling a function of that name. std::size(r) always invokes a function named size (unless r is a raw array). std::empty(r) always invokes a function named empty(unless r is a raw array, in which case it's just false, or r is an initializer_list, in which case r.size() == 0). But ranges::size could under certain circumstances perform ranges::end(r) - ranges::begin(r) (as a fallback if size(r) and r.size() don't exist) just like ranges::empty could under certain circumstances either do ranges::size(r) == 0 or ranges::begin(r) == ranges::end(r). 这篇关于std::ranges::begin 和 std::begin 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-05 23:00
查看更多