C++ std::ranges::begin和std::begin之间的区别是什么?

C++ std::ranges::begin和std::begin之间的区别是什么?,c++,range,c++20,std-ranges,C++,Range,C++20,Std Ranges,和新的有什么区别?(与端部、尺寸等相同) 这两种方法似乎都是一样的: #包括 #包括 #包括 #包括 模板 无效打印信息(常数R和范围) { std::cout有一些差异 首先,ranges::begin(x)适用于所有范围,而std::begin(x)不适用。后者不会在begin上执行ADL查找,因此指定的范围如下: struct R { ... }; auto begin(R const&); auto end(R const&); 不起作用,这就是为什么你必须写这

和新的有什么区别?(与
端部
尺寸
等相同)

这两种方法似乎都是一样的:

#包括
#包括
#包括
#包括
模板
无效打印信息(常数R和范围)
{

std::cout有一些差异

首先,
ranges::begin(x)
适用于所有范围,而
std::begin(x)
不适用。后者不会在
begin
上执行ADL查找,因此指定的范围如下:

struct R {
    ...
};
auto begin(R const&);
auto end(R const&);
不起作用,这就是为什么你必须写这样的东西:

using std::begin, std::end;
auto it = begin(r);
您不必使用
ranges::begin
执行两步操作

其次,
ranges::begin(x)
更安全。ranges引入了借用范围的概念,这是一个可以安全保存其迭代器的范围。例如,
vector
不是借用范围-因为一旦
vector
消失,数据就会消失。
ranges::begin
防止:

auto get_data() -> std::vector<int>;

auto a = std::begin(get_data());    // ok, but now we have a dangling iterator
auto b = ranges::begin(get_data()); // ill-formed
尽管更令人烦恼的是,您有一个迭代器类型,它可能是可递增的、可取消引用的、可比较的等等,但却没有默认构造函数。这不符合C++20的要求,因此
ranges::begin
将失败

第四,
ranges::begin
是一个函数对象,而
std::begin
是一组重载函数模板:

auto f = ranges::begin; // ok
auto g = std::begin;    // error: which std::begin did you want?

第五,某些范围自定义点对象除了调用该名称的函数外,还有其他回退行为。
std::size(r)
始终调用名为
size
的函数(除非
r
是原始数组)。
std::empty(r)
始终调用名为
empty
(除非
r
是一个原始数组,在这种情况下它只是
false
,或者
r
是一个
initializer\u列表
,在这种情况下
r.size()==0
)。但是
ranges::size
可以执行
ranges::end(r)-ranges::begin(r)
(如果
size(r)
r.size()
不存在,则作为一种回退)就像
ranges::empty
可以执行
ranges::size(r)==0
ranges::begin(r)==ranges::end(r)

阅读ranges v3中发生的所有幕后故事总是一件令人愉快的事。因此
ranges::begin
,等等确实使
std::begin
过时了?或者,在某些情况下,人们仍然必须使用
std::begin
而不是
ranges::begin
?@cigien,如果您的迭代器不是默认的可构造迭代器或缺少后缀增量或其他什么,那么
ranges::begin
将由于那些额外的类型检查而拒绝它们。啊,好吧,我假设这样的迭代器是有效的?并且没有违反任何其他规则?@cigien取决于您如何定义“有效”如果它们不是默认可构造的,则它们不是有效的C++20
input\u或\u output\u迭代器。
auto f = ranges::begin; // ok
auto g = std::begin;    // error: which std::begin did you want?