什么是 C 11 中的 lambda 表达式?

新手上路,请多包涵

什么是 C++11 中的 lambda 表达式?我什么时候用一个?他们解决了哪类问题在引入之前是不可能的?

几个例子和用例会很有用。

原文由 Nawaz 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 745
2 个回答

问题

C++ 包含有用的通用函数,例如 std::for_eachstd::transform ,非常方便。不幸的是,它们使用起来也很麻烦,特别是如果您要应用的 函子 对于特定函数是唯一的。

 #include <algorithm>
#include <vector>

namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };
}

void func(std::vector<int>& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);
}

如果你只使用 f 一次并且在那个特定的地方,编写一个完整的课程只是为了做一些微不足道的事情似乎有点过头了。

在 C++03 中,您可能很想编写类似以下内容,以保持函子本地化:

 void func2(std::vector<int>& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

但是这是不允许的, f 不能传递给 C++03 中的 模板 函数。

新的解决方案

C++11 引入了 lambda,允许您编写一个内联的匿名仿函数来替换 struct f 。对于小的简单示例,这可以更清晰地阅读(它将所有内容保存在一个地方)并且可能更易于维护,例如以最简单的形式:

 void func3(std::vector<int>& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Lambda 函数只是匿名函子的语法糖。

返回类型

在简单的情况下,会为您推导出 lambda 的返回类型,例如:

 void func4(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

但是,当您开始编写更复杂的 lambda 表达式时,您将很快遇到编译器无法推断返回类型的情况,例如:

 void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

要解决此问题,您可以使用 -> T 显式指定 lambda 函数的返回类型:

 void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

“捕获”变量

到目前为止,除了传递给其中的 lambda 之外,我们没有使用任何其他变量,但我们也可以在 lambda 中使用其他变量。如果您想访问其他变量,您可以使用捕获子句(表达式的 [] ),迄今为止在这些示例中未使用该子句,例如:

 void func5(std::vector<double>& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });
}

您可以通过引用和值来捕获,您可以分别使用 &= 指定:

  • [&epsilon, zeta] 通过引用捕获 epsilon,按值捕获 zeta
  • [&] 通过引用捕获lambda中使用的所有变量
  • [=] 按值捕获 lambda 中使用的所有变量
  • [&, epsilon] 通过引用捕获 lambda 中使用的所有变量,但按值捕获 epsilon
  • [=, &epsilon] 通过值捕获 lambda 中使用的所有变量,但通过引用捕获 epsilon

生成的 operator() 默认为 const ,默认情况下捕获的将是 const 。这具有相同输入的每次调用都会产生相同结果的效果,但是您可以 将 lambda 标记为 mutable 以请求产生的 operator() 不是 const

原文由 Flexo 发布,翻译遵循 CC BY-SA 4.0 许可协议

C++ 11 引入了 lambda 表达式以允许我们编写一个内联函数,该函数可用于短代码片段

[ capture clause ] (parameters) -> return-type
{
   definition of method
}

通常 lambda 表达式中的 return-type 由编译器本身评估,我们不需要显式指定和 -> return-type 部分可以忽略,但在一些复杂的情况下,如条件语句,编译器无法确定返回类型,我们需要指定。

 // C++ program to demonstrate lambda expression in C++
#include <bits/stdc++.h>
using namespace std;

// Function to print vector
void printVector(vector<int> v)
{
    // lambda expression to print vector
    for_each(v.begin(), v.end(), [](int i)
    {
        std::cout << i << " ";
    });
    cout << endl;
}

int main()
{
    vector<int> v {4, 1, 3, 5, 2, 3, 1, 7};

    printVector(v);

    // below snippet find first number greater than 4
    // find_if searches for an element for which
    // function(third argument) returns true
    vector<int>:: iterator p = find_if(v.begin(), v.end(), [](int i)
    {
        return i > 4;
    });
    cout << "First number greater than 4 is : " << *p << endl;

    // function to sort vector, lambda expression is for sorting in
    // non-decreasing order Compiler can make out return type as
    // bool, but shown here just for explanation
    sort(v.begin(), v.end(), [](const int& a, const int& b) -> bool
    {
        return a > b;
    });

    printVector(v);

    // function to count numbers greater than or equal to 5
    int count_5 = count_if(v.begin(), v.end(), [](int a)
    {
        return (a >= 5);
    });
    cout << "The number of elements greater than or equal to 5 is : "
        << count_5 << endl;

    // function for removing duplicate element (after sorting all
    // duplicate comes together)
    p = unique(v.begin(), v.end(), [](int a, int b)
    {
        return a == b;
    });

    // resizing vector to make size equal to total different number
    v.resize(distance(v.begin(), p));
    printVector(v);

    // accumulate function accumulate the container on the basis of
    // function provided as third argument
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int f = accumulate(arr, arr + 10, 1, [](int i, int j)
    {
        return i * j;
    });

    cout << "Factorial of 10 is : " << f << endl;

    //   We can also access function by storing this into variable
    auto square = [](int i)
    {
        return i * i;
    };

    cout << "Square of 5 is : " << square(5) << endl;
}

输出

4 1 3 5 2 3 1 7
First number greater than 4 is : 5
7 5 4 3 3 2 1 1
The number of elements greater than or equal to 5 is : 2
7 5 4 3 2 1
Factorial of 10 is : 3628800
Square of 5 is : 25

通过从封闭范围访问变量,lambda 表达式可以比普通函数更强大。我们可以通过三种方式从封闭范围中捕获外部变量:

  • 通过引用捕获
  • 按价值捕获
  • 两者都捕获(混合捕获)

用于捕获变量的语法:

  • [&] : 通过引用捕获所有外部变量
  • [=] : 按值捕获所有外部变量
  • [a, &b] :按值捕获 a 并通过引用捕获 b 带有空捕获子句 [ ] 的 lambda 只能访问它本地的那些变量。
     #include <bits/stdc++.h>
    using namespace std;

    int main()
    {
        vector<int> v1 = {3, 1, 7, 9};
        vector<int> v2 = {10, 2, 7, 16, 9};

        // access v1 and v2 by reference
        auto pushinto = [&] (int m)
        {
            v1.push_back(m);
            v2.push_back(m);
        };

        // it pushes 20 in both v1 and v2
        pushinto(20);

        // access v1 by copy
        [v1]()
        {
            for (auto p = v1.begin(); p != v1.end(); p++)
            {
                cout << *p << " ";
            }
        };

        int N = 5;

        // below snippet find first number greater than N
        // [N] denotes, can access only N by value
        vector<int>:: iterator p = find_if(v1.begin(), v1.end(), [N](int i)
        {
            return i > N;
        });

        cout << "First number greater than 5 is : " << *p << endl;

        // function to count numbers greater than or equal to N
        // [=] denotes, can access all variable
        int count_N = count_if(v1.begin(), v1.end(), [=](int a)
        {
            return (a >= N);
        });

        cout << "The number of elements greater than or equal to 5 is : "
            << count_N << endl;
    }

输出:

    First number greater than 5 is : 7
   The number of elements greater than or equal to 5 is : 3

原文由 sun1211 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题