循环到可循环迭代的范围

时间:2015-03-22 14:40:00

标签: c++ c++11 argument-passing c++14

假设我有以下情况

template<typename T>
void func(T&& arg)
{
    for (auto elem : arg) // ***
    {
        // do stuff
    }
}

其中arg是iterabe(向量或初始化列表等)。我对行***感兴趣:以下哪项更好:

auto elem
auto& elem
`const` of the above

我认为选项(3)包含在参数推导中(如果需要的话,auto会将const放在那里)。 func被调用的事实也是如此

func(std::forward<T>(arg)); 

改变什么?

3 个答案:

答案 0 :(得分:5)

在基于范围的auto循环中使用for变量声明几乎总是错误。如果保证范围使用未变异的内置对象,那么它才是正确的。我通常不会在这里使用auto(公平地说,我首先也不会基于范围for,但更喜欢算法)。

使用auto&约束*it对于某个合适类型it的{​​{1}}或T&范围内的迭代器T const&的结果}。例如,它不允许迭代T。如果允许元素变异,那么这是一个合理的选择。使用std::vector<bool>约束auto const&的结果是左值或具有复制构造函数,并将阻止范​​围变异。根据使用情况,这可能是一个合理的选择。

一般情况下,默认选项应为*it,因为除了auto&&之外,*it的结果不会对其进行约束。

所以,总结一下:

  • void如果元素必须内置且未发生变异。
  • for (auto elem: arg)如果元素是左值并且允许变异。
  • for (auto& elem: arg)如果元素是左值但未变异。
  • 在所有不重要的情况下,
  • for (auto const& elem: arg)。我认为始终使用for (auto&& elem: arg)是可以的。

答案 1 :(得分:0)

这完全取决于容器中的内容。

如果容器的值很大,使用引用的重量级对象会更好,因为它可以避免复制它。

另一方面,如果容器的值只是小值,特别是本机数据类型,则显式副本将鼓励更好的编译器优化,因为编译器可以假设在迭代期间,当前使用的值不能通过另一个引用或指针。

答案 2 :(得分:0)

这完全取决于你想做什么以及什么是T的类型。

您应该使用:

for (auto elem : arg)
{
      // do stuff
}

当T是原始类型(要复制便宜)并且您不想修改'arg'集合时。

您应该使用:

for (auto& elem : arg)
{
      // do stuff
}

如果你想修改'arg'集合。

您应该使用:

for (const auto& elem : arg)
{
      // do stuff
}

当T不是原语(复制费用昂贵)时,你保证不会更改'arg'集合。