关于在STL算法中传递C ++ functor / lambda参数的困惑

时间:2017-04-28 07:59:18

标签: c++ c++11 arguments pass-by-reference functor

我喜欢C ++ 11及其将STL算法与lambda结合的能力;它使STL更加平易近人,对每个人都有用。但是我不明白的一件事是STL算法(如function d()... etc)内部关于对象复制或在lambda内部引用(或者你给它的任何函子)的内容。

我的三个问题是:

  1. 是否有任何关于我应该关注lambda / functor中的pass-by-reference和pass-by-value的指南?
  2. 如果你在一个算法中声明一个lambda,它通过引用(std::accumulate)获取它的参数,它是否重要,并且它会比常规变量更优化;或者它只是语法糖,编译器无论如何都会优化它,我可以简单地省略&符号?
  3. C ++标准是否有关于此的任何规定?
  4. 关于问题#2,Godbolt's GCC页面中的快速实验(使用编译标记[](Type &a, Type &b){})似乎建议后者,因为无论我在哪里使用{{{ 1}}或-stc=c++11 -Os;但是,我不知道这些结果是否可以推广到更复杂的类型/对象。

    示例#1:

    [](T i1, T i2)

    示例#2:

    [](T &i1, T &i2)

2 个答案:

答案 0 :(得分:2)

你的问题很广泛,但这是我简明扼要的答案。

1)一般来说,在lambdas或functor中传递by-value和by-reference的指导原则与任何常规函数或方法相同(lambda是为你动态创建的仿函数,这是一个operator()(T)的对象。选择主要针对您的情况,例如,如果lambda / functor需要对其参数的只读访问权限,则tipycally会传递const引用。

2)在接受可调用对象作为参数(以及作为模板参数)的算法中,编译器必须遵守该语言的规则。因此,参数将根据lambda / functor的签名在内部通过值或引用传递。

请记住,复制省略可以进入游戏,但这是一个单独的问题,与您在标准库算法中调用lambda的事实没有直接关系。

int的示例太简单了。我建议你试验一下实际的物体。

3)C ++ Standard为发生复制省略的条件提供了精确的definitions,以及对特定标准库算法的lambda / functor参数签名的要求。

但是,通常不容易知道特定算法的内部实现是否会以满足复制条件的方式调用lambda / functor。

请注意,签名要求具有一定程度的灵活性,例如我们的std::accumulate documentation

  

该功能的签名应与以下内容相同:   Ret fun(const Type1& a,const Type2& b);签名不需要   有const&。

因此您可以根据需要选择传递值或引用。

答案 1 :(得分:0)

在lambdas / functions中,规则与所有C ++中的规则相同。

如果函数的意图是修改调用者的对象,则应该使用非const引用。该函数应使用const&如果它只是使用对象而不更改它。如果要将对象复制/移动到其内部存储中,它应该通过值传递。

如果您传递像int这样的小对象,那么如果您通过值或引用传递则没有任何区别。 当你开始传递一个大对象时,它会对性能产生很大的影响。