假设我有以下情况
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));
改变什么?
答案 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'集合。