最近我发现自己越来越多地使用C++11,过去我会使用迭代器,而现在只要可能我就会使用基于范围的for循环:
std::vector<int> coll(10);
std::generate(coll.begin(), coll.end(), []() { return rand(); } );
C++03:
for (std::vector<int>::const_iterator it = coll.begin(); it != coll.end(); ++it) {
foo_func(*it);
}
C++11:
for (auto e : coll) { foo_func(e); }
但如果集合元素类型是模板参数怎么办?foo_func()
可能会被重载,使用常量引用传递复杂(即复制开销大)的类型,而通过值传递简单的类型:
foo_func(const BigType& e) { ... };
foo_func(int e) { ... };
在我使用上面的C++03风格的代码时,我并没有给这个问题多加思考。我会以相同的方式进行迭代,由于解引用const_iterator会产生一个const引用,所以一切都很好。但是在使用C++11基于范围的for循环时,我需要使用一个const引用循环变量来获得相同的行为:
for (const auto& e : coll) { foo_func(e); }
突然间,我不确定了,如果auto
是一种简单类型(如幕后指针实现引用),这是否会引入不必要的汇编指令。
但编译一个样例应用程序证实了对于简单类型没有额外开销,并且这似乎是在模板中使用基于范围的for循环的通用方式。如果不是这种情况,那么boost::call_traits::param_type就是解决方法。
问题:标准中有任何保证吗?
(我意识到这个问题与基于范围的for循环无关。当使用const_iterator时,这个问题也存在。)
auto const&
。 ;) - Xeoconst
]引用,那么符号T&&
会推导出该值而不是该值的引用。 - Dietmar Kühlauto&&
都将始终是一个引用。如果它确实产生了一个值,那么它只是一个右值引用。(注意:我可能误解了你的评论。) - Xeoauto&&
的有趣观点。在移动语义和完美转发的上下文中,我对右值引用相对容易掌握;但是我没有考虑过在这种情况下使用它们。那么for (const auto&& e : coll) { ... }
怎么样? - Daniel Gehrigere
的类型不是值类型,而是某个类型T
的T&&
。当使用auto const& e
时,e
的类型为T const&
。要真正利用这种差异,可能需要使用f(std::forward<decltype(e)>(e))
,这并不是很美观。 - Dietmar Kühlauto const&&
不会成为通用引用,只会绑定到右值。 - Xeo