gpt4 book ai didi

c++ - std::begin 和 R 值

转载 作者:可可西里 更新时间:2023-11-01 18:35:42 25 4
gpt4 key购买 nike

最近我试图修复一个非常困难的 const-correctness 编译器错误。它最初表现为 Boost.Python 深处的多段模板呕吐错误。

但这无关紧要:这一切都归结为以下事实:C++11 std::beginstd::end 迭代器函数没有重载到取 R 值。

std::begin 的定义是:

template< class C >
auto begin( C& c ) -> decltype(c.begin());

template< class C >
auto begin( const C& c ) -> decltype(c.begin());

因此,由于没有 R 值/通用引用重载,如果您将 R 值传递给它,您将获得一个 const 迭代器。

那我为什么要关心呢?好吧,如果你有某种“范围”容器类型,即像“ View ”、“代理”或“切片”或一些呈现另一个容器的子迭代器范围的容器类型,通常很方便使用 R 值语义并从临时切片/范围对象中获取非常量迭代器。但是对于 std::begin,您就不走运了,因为 std::begin 将始终为 R 值返回一个常量迭代器。这是一个老问题,在 C++11 给我们 R 值之前的一天,C++03 程序员经常对它感到沮丧——即临时对象总是绑定(bind)为 const 的问题。

那么,为什么 std::begin 没有定义为:

template <class C>
auto begin(C&& c) -> decltype(c.begin());

这样,如果 c 是常量,我们将得到一个 C::const_iterator,否则将得到一个 C::iterator

一开始我以为是为了安全。如果您将临时变量传递给 std::begin,如下所示:

auto it = std::begin(std::string("temporary string")); // never do this

...你会得到一个无效的迭代器。但后来我意识到这个问题在当前的实现中仍然存在。上面的代码只会返回一个无效的 const 迭代器,在取消引用时可能会出现段错误。

那么,为什么 std::begin 被定义为采用 R 值(或更准确地说,一个 Universal Reference )?为什么有两个重载(一个用于 const,一个用于 non-const)?

最佳答案

The above code would simply return an invalid const-iterator

不完全是。迭代器将一直有效,直到迭代器引用的临时对象是在词法上创建的完整表达式的末尾。所以像

std::copy_n( std::begin(std::string("Hallo")), 2,
std::ostreambuf_iterator<char>(std::cout) );

仍然是有效代码。当然,在您的示例中,it 在语句末尾无效。

修改临时值或 xvalue 有什么意义?这可能是范围访问器的设计者在提出声明时考虑的问题之一。他们没有考虑 .begin().end() 返回的迭代器在其生命周期结束后仍然有效的“代理”范围;也许正因为如此,在模板代码中,它们无法与正常范围区分开来 - 我们当然不想修改临时的非代理范围,因为那毫无意义并且可能会导致混淆。

但是,您不需要首先使用 std::begin,而是可以使用 using 声明来声明它们:

using std::begin;
using std::end;

并使用 ADL。通过这种方式,您可以为 Boost.Python(o.s.)使用的类型声明 namespace 范围的 beginend 重载,并规避 std::begin< 的限制。例如

iterator begin(boost_slice&& s) { return s.begin(); }
iterator end (boost_slice&& s) { return s.end() ; }

// […]

begin(some_slice) // Calls the global overload, returns non-const iterator

Why have two overloads (one for const and one for non-const)?

因为我们仍然希望支持右值对象(它们不能被 T& 形式的函数参数接受)。

关于c++ - std::begin 和 R 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26959953/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com