在前TS代码中,我可能会执行以下操作来获取对ForwardIterator值的(可能是可修改的)引用:
auto &val = *it;
这也将在此类迭代器的基于范围的for
循环中使用:
for(auto &val : some_range)
但是,在基于C ++ 20和Range TS的代码中,我看到在这些位置有许多auto&&
用法。我从语言的角度理解auto&&
在做什么。我不明白的是为什么auto&
应该可以正常工作时在这些地方使用它?这种性质的大多数代码都不会转发引用,那么为什么要使用转发引用来捕获它呢?
答案 0 :(得分:11)
使用此习惯用法是因为Range TS和C ++ 20等效的实际上需要该习惯用法。之所以要这样做,是因为代理迭代器现在是所有迭代器类别的合法构造。
代理迭代器的operator*
不返回value_type&
;它会返回一个像引用一样起作用的对象的prvalue。因此,如果您尝试使用auto&
存储对该值的引用,则代码将无法使用代理迭代器进行编译。
Range TS的迭代器概念从不要求operator*
的返回值实际上是语言参考。可读概念仅要求返回值可转换为value_type
。可写概念仅要求将value_type
分配给返回值。
因此,在范围功能下从各种迭代器获取引用的代码现在必须使用auto&&
,它可以绑定到prvalue,而无需使其成为const
。因此,在处理范围时,如果要获取对该值的可能是非常量的引用,则auto&&
是最方便的方法。如果只需要const
引用,则可以继续使用const auto &
。
请注意,auto&&
还处理直接从其value_type
返回operator*
类型的prvalue的迭代器。显然,这些仅对Readable迭代器有用,但是它们非常有用。最简单的示例是一个迭代器,用于对一定数量的整数进行计数。迭代器返回int
,而不是对某些内存的引用。由于对返回语言参考没有严格要求,因此此类迭代器可以是Range TS中的RandomAccessIterators。
这样的迭代器对于正则表达式匹配也很有意义。当前的regex_iterator
返回对内部对象的引用;对于ForwardIterator来说这是必需的。取而代之的是,通过operator*
进行搜索并将匹配对象作为prvalue返回,它可以变得更小。但是旧系统不允许这样做。
鉴于这种迭代器,auto&
不能用于捕获对其结果的“引用”。