C++ Lambda 表达式:捕获子句与参数列表;关键的区别是什么?

Rez*_*Rez 13 c++ lambda parameter-list

我正在学习 C++ 中的 Lambda 表达式,尽管我不是 C/C++ 的新手。我很难看到使用捕获子句与传入参数列表的老式参数将变量绘制到 Lambda 主体中进行操作的相对优点。我熟悉它们的语法差异以及每个中允许和不允许的内容,但只是不知道其中一个比另一个更有效?

如果您有内幕知识,或者对 Lambda 正在发生的事情有更好的了解,请告诉我。

非常感谢,雷扎。

for*_*818 5

考虑到 lambda 基本上只是函子的语法糖。例如

int x = 1;
auto f = [x](int y){ return x+y; };
Run Code Online (Sandbox Code Playgroud)

或多或少相当于

struct add_x {
    int x;
    add_x(int x) : x(x) {}
    int operator()(int y) const { return x+y; }
}

int x = 1;
add_x f{x};
Run Code Online (Sandbox Code Playgroud)

当你传递 lambda 时,差异就会变得明显,例如

template <typename F> 
void foo(F f) {
    for (int i=0;i<10;++i) std::cout << f(i) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

类似的函数是使用 lambda 的主要动机之一,并且该函数(在本例中仅隐式地)指定了预期的签名。您可以foo致电

foo(f);
Run Code Online (Sandbox Code Playgroud)

但是如果你的仿函数 / lambda 也将作为x参数,那么你将无法将它传递给foo.

TL;DR:捕获的变量构成 lambda 的状态,而参数就像普通函数参数一样。


Vla*_*cow 2

区别在于相同的捕获可以与不同的参数一起使用。

考虑下面的简单例子

#include <iostream>
#include <iterator>
#include <algorithm>

int main() 
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    const int N = 10;

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    std::transform( std::begin( a ), std::end( a ), std::begin( a ),
                    [=]( const auto &item ) { return N * item; } );

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序输出是

0 1 2 3 4 5 6 7 8 9 
0 10 20 30 40 50 60 70 80 90 
Run Code Online (Sandbox Code Playgroud)

lambda 的参数由算法 std::transform 提供。该算法无法将乘数 N 传递给 lambda。因此您需要捕获它,并且乘数将与传递给 lambda 的任何参数一起使用。