【问题标题】:Parentheses at the end of a C++11 lambda expressionC++11 lambda 表达式末尾的括号
【发布时间】:2012-09-30 16:00:25
【问题描述】:

我对使用 C++11 lambda 时遇到的一些示例感到困惑。 例如:

#include <iostream>
#include <string>

using namespace std;

int main()
{ 
        cout << []()->string{return "Hello World 1!";}() << endl;

        []{cout << "Hello World 2!" << endl;}();

        string result = [](const string& str)->string {return "Hello World " + str;}("2!");
        cout << "Result: " << result << endl;

        result = [](const string& str){return "Hello World " + str;}("3!");
        cout << "Result: " << result << endl;

        string s;
        [&s](){s = "Hello World 4!";};   // does not work
        cout << s << endl; 
        [&s](){s = "Hello World 4!";}(); // works!
        cout << s << endl;

        return 0;
}

我无法弄清楚最后的括号在做什么。他们是否作为构造函数实例化了一个 lambda?鉴于 lambda 的模板是:

[capture_block](parameters) mutable exception_specification -> return_type {body}

让我感到困惑的是,这些实例需要这些括号才能工作。有人能解释一下为什么需要它们吗?

【问题讨论】:

  • 这是一个光辉的例子,说明为什么 lambdas 是应该谨慎使用的东西。我必须阅读该代码大约 5 次才能理解全部意图。
  • @Richard:抱歉,不,不是。这是如何误用它们的主要例子。您通常不会以与创建它完全相同的表达式来调用它。
  • @leemes - 通常的 C 和 C++ hello world 程序远没有这段代码那么密集。
  • @Xeo 定义并立即使用 lambda 的一个有用示例是为 const 变量分配一个需要一些复杂初始化代码的值:const int x = []{ some init code }(); 所以你不需要一个单独的函数来在其余生中使x const。但是,我可能是错的(再次):)
  • @leemes:我特别说过你通常不要立即调用它。 ;) 使用一次性函数初始化静态成员也是如此。

标签: c++ lambda c++11 parentheses


【解决方案1】:

好吧,鉴于 lambda 表达式基本上是一个匿名函数,最后的括号只是调用这个函数而已。所以

result = [](const string& str){return "Hello World " + str;}("3!");

就相当于

auto lambda = [](const string& str){return "Hello World " + str;};
string result = lambda("3!");

这对于没有参数的 lambda 也是一样的,比如 in

cout << []()->string{return "Hello World 1!";}() << endl;

否则(如果未调用)会尝试输出 lambda 表达式,该表达式本身不起作用。通过调用它,它只会输出结果 std::string。

【讨论】:

    【解决方案2】:

    他们正在调用函数对象!

    分两个阶段:

    auto l = []()->string{return "Hello World 1!";}; // make a named object
    l(); // call it
    

    一个 lambda 表达式的计算结果是一个函数对象。由于没有采用这样一个函数对象的operator&lt;&lt; 重载,因此如果您没有调用它来生成std::string,则会出现错误。

    【讨论】:

    • 这真的叫函数object吗?我认为应该区分函数对象(= 实现 operator() 以表现类似于函数的对象)和 lambda 函数。不同的概念,不同的用法,相似的用例。
    • @leemes:除了,lambdas 是函数对象。他们实现operator()。
    • @leemes:首先,它们不是源自std::function,其次是check this link。 lambda 表达式在表达式的范围内创建一个未命名的唯一类型和该类型的对象,其中包含operator() 以及以某种方式捕获的内容。在编写 lambda 表达式时,将使用此对象。
    • @leemes: std::function(和它的 boost 等价物)允许 storage 任何给定的可调用实体。一个 lambda 派生的函数对象就是这样一个可调用的实体,所以它可以被存储。 :)
    • @leemes std::function 是一个存储函数对象(或任何可调用对象)的容器,它们不是从它派生的,实际上没有人应该从 std::function 派生(至少不是为了简单的日常)原因)。
    猜你喜欢
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 2013-10-15
    • 2020-04-15
    • 1970-01-01
    相关资源
    最近更新 更多