有什么理由不使用全局Lambda?

时间:2019-12-15 15:24:31

标签: c++ lambda

我们有一个函数使用了自身内部的非捕获lambda,例如:

void foo() {
  auto bar = [](int a, int b){ return a + b; }

  // code using bar(x,y) a bunch of times
}

现在其他地方都需要由lambda实现的功能,因此我将把lambda从foo()提升到全局/命名空间范围。我可以将其保留为lambda,使其成为复制粘贴选项,也可以将其更改为适当的功能:

auto bar = [](int a, int b){ return a + b; } // option 1
int bar(int a, int b){ return a + b; } // option 2

void foo() {
  // code using bar(x,y) a bunch of times
}

将其更改为适当的功能是微不足道的,但是这使我想知道是否有某些理由 not 将其保留为lambda?是否有理由不只是在各处使用lambda而不是“常规”全局函数?

6 个答案:

答案 0 :(得分:45)

我可以想到一些您希望避免将全局lambda替换为常规函数的现成原因的原因:

    常规函数可以重载; lambda不能(但是,有一些技术可以模拟这一点)
  • 尽管它们类似于函数,但即使是这样的非捕获型lambda也会占用内存(非捕获型通常为1个字节)。
    • 正如评论中指出的那样,现代编译器将根据 as 规则
    • 来优化此存储。

“为什么不应该使用lambda代替有状态函子(类)?”

  • 与lambda相比,类仅具有更少的限制,因此应该成为您要了解的第一件事
    • (公共/私有数据,重载,帮助器方法等)
  • 如果lambda具有状态,则更难于推断何时变为全局状态。
    • 我们宁愿在尽可能小的范围内创建类的 instance
  • 将非捕获的lambda转换为函数指针已经很困难,并且lambda在捕获中指定任何内容都是不可能的。
    • 类为我们提供了一种直接创建函数指针的方法,这也是许多程序员更喜欢的
  • 带有任何捕获的Lambda不能被默认构造(在C ++ 20中。以前在任何情况下都没有默认构造器)

答案 1 :(得分:45)

一个不使用全局Lambda的重要原因是:这是不正常的。

C ++的常规函数​​语法自C语言诞生以来就已经存在。数十年来,程序员都知道语法的含义以及它们的工作方式(尽管公认,整个函数到指针的衰减有时甚至会咬住经验丰富的程序员)。如果具有“完全新手”以外的任何技能水平的C ++程序员都可以看到函数定义,那么他们知道自己正在获得什么。

全局lambda完全是另一种野兽。它具有与常规功能不同的行为。 Lambda是对象,而功能不是。它们具有一个类型,但是该类型不同于其功能的类型。依此类推。

因此,现在,您已经提高了与其他程序员交流的门槛。如果C ++程序员想要了解该函数的功能,则需要了解它们。是的,这是2019年,所以一个体面的C ++程序员应该对lambda的外观有所了解。但这仍然是一个更高的标准。

即使他们理解它,该程序员的脑海中的问题仍将是...为什么此代码的编写者以这种方式编写它?而且,如果您对这个问题没有一个好的答案(例如,因为您明确地想要禁止重载,如Ranges定制点中所示),则应使用通用机制。

在适当的情况下,将预期的解决方案优先于新颖的解决方案。使用最简单的方法来表达观点。

答案 2 :(得分:7)

询问后,我想到了一个不这样做的原因:由于这些是变量,因此它们容易发生静态初始化顺序失败https://isocpp.org/wiki/faq/ctors#static-init-order),这可能会导致错误。线。

答案 3 :(得分:6)

  

是否有理由不只是在各处使用lambda而不是“常规”全局函数?

某种程度的复杂性问题要求至少具有相同复杂性的解决方案。但是,如果针对同一问题的解决方案不太复杂,那么实际上没有理由使用更复杂的解决方案。为什么要引入不需要的复杂性?

在lambda和函数之间,函数只是两者中不太复杂的一种。您不必证明不使用lambda。您必须证明使用一个。 lambda表达式引入了一个闭包类型,它是具有所有常用特殊成员函数的未命名类类型,函数调用运算符,在这种情况下,还包括隐式转换运算符到函数指针,并创建该类型的对象。从lambda表达式中复制初始化全局变量不仅仅定义一个函数,还执行了很多的工作。它定义了具有六个隐式声明的函数的类类型,定义了另外两个运算符,并创建了一个对象。编译器必须做更多的事情。如果您不需要lambda的任何功能,请不要使用lambda…

答案 4 :(得分:5)

Lambda是anonymous functions

如果您使用命名的lambda,则意味着您基本上是在使用命名的匿名函数。为了避免这种矛盾,您不妨使用一个函数。

答案 5 :(得分:4)

  

是否出于某些原因不将其保留为lambda?是否有理由不只是在各处使用lambda而不是“常规”全局函数?

我们过去使用函数而不是全局函子,因此破坏了一致性和最小惊讶的原理

主要区别在于:

  • 函数可以重载,而函子不能。
  • 功能可以通过ADL找到,而不是函子。