C++ 基于范围的声明的正确样式

C++ 基于范围的声明的正确样式,c++,for-loop,c++11,perfect-forwarding,C++,For Loop,C++11,Perfect Forwarding,提到了基于范围的C++11的明显的惯用用法 for (auto& elem: container) { // do something with elem } 不过,我一直怀疑你应该使用哪种参考资料。输入迭代器可能返回右值。虽然可以将auto引入的隐式类型推断为绑定到右值的const,但似乎没有发生这种情况 使用完美转发是否是最佳的常规做法 for (auto && elem: container) { // do something with elem }

提到了基于范围的C++11的明显的惯用用法

for (auto& elem: container) {
  // do something with elem
}
不过,我一直怀疑你应该使用哪种参考资料。输入迭代器可能返回右值。虽然可以将
auto
引入的隐式类型推断为绑定到右值的
const
,但似乎没有发生这种情况

使用完美转发是否是最佳的常规做法

for (auto && elem: container) {
  // do something with elem
}

我看不出有什么坏处,但它看起来有点太可爱了。也许我还没有写足够的C++11。

首先,关于如何使用
auto
的一些一般性建议,这些建议并不是特定于的范围<如果初始值设定项是引用临时值的xvalue,则code>auto&可能会有问题,因为在这种情况下可能不会应用生存期扩展。更简单地说,使用代码:

// Pass-through identity function that doesn't construct objects
template<typename T>
T&&
id(T&& t)
{ return std::forward<T>(t); }

// Ok, lifetime extended
// T {} is a prvalue
auto&& i = T {};

T* address = &i;

// Still ok: lifetime of the object referred to by i exceed that of j
// id(whatever) is an xvalue
auto&& j = id(std::move(i));

// No other object is involved or were constructed,
// all those references are bound to the same object
assert( &j == address );

// Oops, temporary expires at semi-colon
// id(whatever) is an xvalue, again
auto&& k = id(T {});
我们现在需要问问自己,如果
*b
是一个xvalue(即迭代器类型有一个
操作符*
返回
值类型&&
,例如使用
std::move_迭代器&
)该怎么办?然后它必须引用一个比
ref
更长寿的对象,因为行
auto&&ref=*b不涉及临时的。因此它是安全的。否则,如果
*b
是一个PR值(即迭代器类型有一个
操作符*
返回
T
,用于某些对象类型
T
),则临时对象的生存期将延长到循环体的其余部分。在所有情况下,您都是安全的(在这种情况下,
*b
是一个左值,留给读者作为练习)


我个人大量使用
自动和&
,有或没有范围。但每次我都会问自己,初始值设定项是否是xvalue,如果是,所指内容的生命周期是什么。

对于那些不能享受基于范围的For的可怜的MSVC10用户,同样的问题也适用于
BOOST\u FOREACH
自动
从不
const
。你需要说
自动常量&
。另外,
auto&&
不是一个右值参考,而是一个“通用参考”。@KerrekSB这是一个很好的信息,
const
。我从来没有说过关于右值引用的任何事情;v) 我应该补充一点,我并不是真的指“永远”:当然
constinta=1;自动&ra=a按预期工作。但是
auto
永远不会变得比它需要的更稳定。@KerrekSB你能澄清一下吗
const
是在函数参数上下文中推导出来的,而
auto
就是根据它定义的,没有例外。这似乎很好:int const i=5;自动&x=i编辑哈哈,好的:v)。好吧,在任何情况下,它都不会猜测左值引用应该被设置为const以绑定到右值。很好的信息。另一个透视图…函数可以返回xvalue的唯一临时变量是右值参数
begin
end
不接受任何参数,因此转发它们的结果是安全的。@PotatosWater在本例中,感兴趣的是
*b
(实际上不接受参数,更不用说您正确分析的临时参数)
begin
end
确实接受参数,但它们只适用于左值。是的,我指的是
begin
end
成员,并且排除
,因为它是左值
operator*
接受的参数与
begin
end
的含义基本相同。但这才是最重要的。
{
    using std::begin;
    using std::end;
    auto&& range = init;
    for(auto b = begin(range), e = end(range); b != e; ++b) {
        auto&& ref = *b;
        /* body */
    }
}