这个代码块[=,&i]()mutable {}的含义是什么?

5

我正在参加一项C++测试,下面有一个奇怪的代码块,我不理解。在这里,i是一个intcode是一个char

[=,&i]()mutable
{
  i++;
  code = 'b';
  std::cout << "i:" <<i<<"""code:"<<code <<cout::endl;
}();

我不知道如何解释这段代码,它看起来并不像典型的C++代码块。我已经在网上搜索了相关信息,但没有找到其他类似的代码风格。

这段代码是什么意思?


3
这是一个包含mutable关键字的非典型lambda定义。能否请您提供更多上下文信息? - πάντα ῥεῖ
2
阅读有关lambda表达式的内容。 - James Adkison
2
欢迎来到 Stack Overflow!我稍微整理了一下你的问题,让它更易于阅读。 - templatetypedef
这是什么测试?你能提供一个链接吗? - David G
@πάνταῥεῖ 这就是我所拥有的,恐怕没有更多了。 - lzrobbytan
@templatetypedef 感谢您的好意!通过这篇文章,我刚刚度过了一次愉快的开场体验。 - lzrobbytan
3个回答

7

这是一个lambda函数,是2011年添加到该语言中的一项功能。

  • =表示外部变量的副本在内部可用。
  • &i表示尽管如上所述,特别是i实际上是按引用可用的。
  • mutable关键字允许在函数体内修改code副本。
  • 尾随的()在声明后立即“运行”函数。

按照现有的写法,我看不出使用lambda的特定原因。看起来有人已经成功地达到了他们的目标:让你感到困惑。


4
我同意这段代码看起来过于复杂。OP - 如果你担心自己是否能理解正在查看的内容,不用担心 - 实际的C++代码很少会出现那种类型的代码。 - templatetypedef
我在商业领域有5年的C ++编程经验,认为自己知道关于lambda的所有内容,但从未在此上下文中见过“mutable”。活到老学到老! - Violet Giraffe
@VioletGiraffe:今天我也学到了关于mutable lambda的知识,多亏了你:) 我以前不知道在这种情况下需要使用这个关键字。再说一遍,除了在SO上,我实际上并没有进行任何C++11开发... - Lightness Races in Orbit
@LightnessRacesinOrbit 谢谢您,先生。您在商业C++开发中有使用过它吗?我只在C#中使用Lambda来创建一个独立线程的工作任务,以便用于excel-dna。 - lzrobbytan
@templatetypedef明白了。但最好了解这个,以防在工作面试中遇到。谢谢。 - lzrobbytan
@lzrobbytan:不,我们工作使用的是C++03。但巧合的是,就在今天,我开始制定迁移计划,以便更新我们的工具。 - Lightness Races in Orbit

2

我将逐步解释这部分内容,因为原始代码可能会令人困惑,表达式是一个lambda表达式,我不会花太多时间讲它,但你可以将其视为内联定义的函数对象。尝试运行以下代码开始:

#include <iostream>
using namespace std;

int main() {
    auto function_object = []() {
        cout << "This is a lambda" << endl;
    };
    function_object(); // This will print the above

    return 0;
}

你的问题中的lambda表达式通过引用成员变量 i ,并且lambda函数体内引用的其他所有内容都是通过值从外部作用域获取的。这就是[=,&i]的含义。
紧随其后的()是一个常规的函数参数表达式,类似于以下括号。
void function() {};

所以你可以将lambda更改为以下内容:
[](int a) {...}(12); 

这将使用参数12调用lambda函数。

大括号中的部分通常是函数体。当花括号关闭时,lambda函数就被创建了。因此,您可以认为包括和在内的所有内容都是lambda函数的构造函数的一部分。然后,最后一对括号就像任何其他函数一样调用lambda函数。

我没有提到的另一件事是mutable关键字。默认情况下,假设lambda函数不能更改其成员变量的值。您需要向lambda函数添加可变性,以传达给编译器它将修改其成员变量。

您可能需要在其他地方学习lambda函数。

一些参考资料: http://en.cppreference.com/w/cpp/language/lambda http://www.cprogramming.com/c++11/c++11-lambda-closures.html

当我最初尝试理解lambda函数时,我阅读了第二个链接,但现在每次我对lambda函数的语法有疑问时都会去cppreference!

尝试编译和运行以下代码片段。这些是一些示例,可能有助于您更好地理解代码。

#include <iostream>
using namespace std;

int main() {
    []() {
        cout << "This is a lambda :)" << endl;
    }();

    auto func = []() {
        cout << "This is another lambda that is stored as a functor in a variable" << endl;
    };
    func();

    int a{10};
    [=]() mutable {
        cout << "I have captured the value of a from the surrounding scope by value " << a << endl;
        a = 20;
    }();

    [&a]() { // notice mutable is not here
        cout << "Here a is captured by reference " << a << endl;
        a = 100;
    }();
    cout << a << endl; // outputs 100

    return 0;
}

1
非常感谢你,Curious。我也尝试了你所有的代码来增强我的理解。它们非常有帮助。我希望将来在C++中使用时能够遇到这种情况。我只在C#中使用过lambda表达式... - lzrobbytan

0

这是一个通过拷贝(等号=)捕获所有内容并显式引用变量i(取地址符&i)的lambda函数,然后在声明它后立即调用。

如果这看起来不像典型的C++代码,那么您可能落后于游戏几年,因为这是完全合法的C++11 / 14(及更高版本)代码。


3
“完全正常”?以目前的写法,我会在代码审查中坚决拒绝。 - Lightness Races in Orbit
也许我应该说“语法完全没问题”。我猜测OP只熟悉C++98,所以看起来很奇怪。我并不是在评论代码本身的质量 - 只是说语法没有什么不寻常的 - C++11现在已经有5年历史了,应该是常识(在我看来)。 - Jesper Juhl
我估计在全球教育机构中,这种技术至少需要大约30年才能普及开来。请记住,印度的学校仍然教授1989年的一种原始C++方言(在模拟DOS上!)...... 这比实际标准化的C++还要早近十年! - Lightness Races in Orbit
如果这是真的(我并不是说它不是),那就太疯狂了。 - Jesper Juhl
1
@LightnessRacesinOrbit我可以证明这是完全正确的。我用过Turbo C++,而且我3年前才从高中毕业。 - Curious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接