金沙js333娱乐场兰姆da函数与表达式

在 C++ 11 中,lambda 表达式(通常称为
“lambda”)是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法。
Lambda 通常用于封装传递给算法或异步方法的少量代码行。 本文定义了 lambda
是什么,将 lambda
与其他编程技术进行比较,描述其优点,并提供一个基本示例。
Lambda 表达式的各部分 ISO C++ 标准展示了作为第三个参数传递给 std::sort() 函数的简单
lambda:

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。

函数是一组一起执行一个任务的语句。每个 C++
程序都至少有一个函数,即主函数 main()
,所有简单的程序都可以定义其他额外的函数。

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
 std::sort(x, x + n,
 // Lambda expression begins
 [](float a, float b) {
  return (std::abs(a) < std::abs(b));
 } // end of lambda expression
 );
}

Lambda 表达式把函数看作对象。

  • 划分通常是根据每个函数执行一个特定的任务来进行的。
  • 函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
  • 函数还有很多叫法,比如方法、子例程或程序,等等
  • C++ 标准库提供了大量的程序可以调用的内置函数

此图显示了 lambda 的组成部分:

Lambda
表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

定义函数

return_type function_name( parameter list )
{
   body of the function
}

// 函数返回两个数中较大的那个数

int max(int num1, int num2) 
{
   // 局部变量声明
   int result;

   if (num1 > num2)
      result = num1;
   else
      result = num2;

   return result; 
}

金沙js333娱乐场 1

Lambda函数的语法定义如下:

函数声明

函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。

return_type function_name( parameter list );

int max(int num1, int num2);

//在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:
int max(int, int);
  1. Capture 子句(在 C++ 规范中也称为 lambda 引导。)
  2. 参数列表(可选)。 (也称为 lambda 声明符)
  3. 可变规范(可选)。
  4. 异常规范(可选)。
  5. 尾随返回类型(可选)。
  6. “lambda 体”

[capture](parameters) mutable ->return-type{statement}

调用函数

调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。

#include <iostream>
using namespace std;

// 函数声明
int max(int num1, int num2);

int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
   int ret;

   // 调用函数来获取最大值
   ret = max(a, b);

   cout << "Max value is : " << ret << endl;

   return 0;
}

// 函数返回两个数中较大的那个数
int max(int num1, int num2) 
{
   // 局部变量声明
   int result;

   if (num1 > num2)
      result = num1;
   else
      result = num2;

   return result; 
}

Capture 子句

其中:

函数参数

形式参数:就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。

当调用函数时,有两种向函数传递参数的方式:
默认情况下,C++ 使用传值调用来传递参数。

调用类型 描述
传值调用 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
指针调用 该方法把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
引用调用 该方法把参数的引用复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

Lambda 可在其主体中引入新的变量(用
C++14),它还可以访问(或“捕获”)周边范围内的变量。 Lambda 以 Capture
子句(标准语法中的 lambda
引导)开头,它指定要捕获的变量以及是通过值还是引用进行捕获。 有与号 (&)
前缀的变量通过引用访问,没有该前缀的变量通过值访问。
空 capture 子句 [ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。
可以使用默认捕获模式(标准语法中的 capture-default)来指示如何捕获
lambda 中引用的任何外部变量:[&] 表示通过引用捕获引用的所有变量,而
[=] 表示通过值捕获它们。
可以使用默认捕获模式,然后为特定变量显式指定相反的模式。 例如,如果
lambda 体通过引用访问外部变量 total 并通过值访问外部变量 factor,则以下
capture 子句等效:

 [capture]:捕捉列表。捕捉列表总是出现在 lambda
表达式的开始处。事实上,[] 是 lambda
引出符。编译器根据该引出符判断接下来的代码是否是 lambda
函数。捕捉列表能够捕捉上下文中的变量供 lambda 函数使用。

参数的默认值

这是通过在函数定义中使用赋值运算符来为参数赋值的。调用函数时,如果未传递参数的值,则会使用默认值,如果指定了值,则会忽略默认值,使用传递的值。

#include <iostream>
using namespace std;

int sum(int a, int b=20)
{
  int result;

  result = a + b;

  return (result);
}

int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
   int result;

// 调用函数来添加值
   result = sum(a, b);
   cout << "Total value is :" << result << endl;

   // 再次调用函数
   result = sum(a);
   cout << "Total value is :" << result << endl;

   return 0;
}
[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]

 (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号
() 一起省略。

Lambda 函数与表达式

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。

Lambda 表达式把函数看作对象。Lambda
表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

[capture](parameters)->return-type{body}

[](int x, int y){ return x < y ; }

//如果没有返回值可以表示为:
[capture](parameters){body}

[]{ ++global_x; } 

[](int x, int y) -> int { int z = x + y; return z + x; }

在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。
与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:

[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

另外有一点需要注意。对于[=]或[&]的形式,lambda 表达式可以直接使用
this 指针。但是,对于[]的形式,如果要使用 this 指针,必须显式传入:

[this]() { this->someFunc(); }();
  • [capture]:捕捉列表。捕捉列表总是出现在 lambda
    表达式的开始处。事实上,[] 是 lambda
    引出符。编译器根据该引出符判断接下来的代码是否是 lambda
    函数。捕捉列表能够捕捉上下文中的变量供 lambda 函数使用。
  • (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号
    () 一起省略。
  • mutable:mutable 修饰符。默认情况下,lambda 函数总是一个 const
    函数,mutable
    可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)。
  • ->return_type:返回类型。用追踪返回类型形式声明函数的返回类型。出于方便,不需要返回值的时候也可以连同符号
    ->
    一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
  • {statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
    在 lambda
    函数的定义式中,参数列表和返回类型都是可选部分,而捕捉列表和函数体都可能为空,C++
    中最简单的 lambda 函数只需要声明为:

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each(v.begin(), v.end(), [&even_count](int val){
    if(!(val & 1)){
        ++ even_count;
    }
});
std::cout << "The number of even is " << even_count << std::endl;
int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 10; });  

int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x < 10; });  

int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 5 && x<10; });  


// 定义简单的lambda表达式
auto basicLambda = [] { cout << "Hello, world!" << endl; };

// 调用
basicLambda();
// 输出:Hello, world!

// 指明返回类型
auto add = [](int a, int b) -> int { return a + b; };

// 自动推断返回类型
auto multiply = [](int a, int b) { return a * b; };
int sum = add(2, 5);   // 输出:7
int product = multiply(2, 5);  // 输出:10

使用 capture-default 时,只有 lambda 中提及的变量才会被捕获。
如果 capture 子句包含 capture-default&,则该 capture 子句的 identifier
中没有任何 capture 可采用 & identifier 形式。 同样,如果 capture
子句包含 capture-default=,则该 capture 子句的 capture 不能采用 =
identifier 形式。 identifier 或 this 在 capture
子句中出现的次数不能超过一次。 以下代码片段给出了一些示例。

 mutable:mutable 修饰符。默认情况下,lambda 函数总是一个 const
函数,mutable
可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)。

struct S { void f(int i); };

void S::f(int i) {
 [&, i]{}; // OK
 [&, &i]{}; // ERROR: i preceded by & when & is the default
 [=, this]{}; // ERROR: this when = is the default
 [i, i]{}; // ERROR: i repeated
}

 ->return_type:返回类型。用追踪返回类型形式声明函数的返回类型。出于方便,不需要返回值的时候也可以连同符号
->
一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。

capture 后跟省略号是包扩展,如以下可变参数模板示例中所示:

 {statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。

template<class... Args>
void f(Args... args) {
 auto x = [args...] { return g(args...); };
 x();
}

在 lambda
函数的定义式中,参数列表和返回类型都是可选部分,而捕捉列表和函数体都可能为空,C++
中最简单的 lambda 函数只需要声明为:

要在类方法的正文中使用 lambda 表达式,请将 this 指针传递给 Capture
子句,以提供对封闭类的方法和数据成员的访问权限。 有关展示如何将 lambda
表达式与类方法一起使用的示例,请参阅 Lambda
表达式的示例中的“示例:在方法中使用 Lambda 表达式”。
在使用 capture 子句时,建议你记住以下几点(尤其是使用采取多线程的 lambda
时):
引用捕获可用于修改外部变量,而值捕获却不能实现此操作。
(mutable允许修改副本,而不能修改原始项。)
引用捕获会反映外部变量的更新,而值捕获却不会反映。
引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。 当 lambda
以异步方式运行时,这一点尤其重要。 如果在异步 lambda
中通过引用捕获本地变量,该本地变量将很可能在 lambda
运行时消失,从而导致运行时访问冲突。

[]{};

发表评论

电子邮件地址不会被公开。 必填项已用*标注