• 【C++11】新特性——Lambda函数


    本篇文章由:http://www.sollyu.com/c11-new-lambda-function/

    文章列表

    本文章为系列文章

    【C++11】新特性——auto的使用 http://www.sollyu.com/c11-new-features-auto/

    【C++11】新特性——Lambda函数 http://www.sollyu.com/c11-new-lambda-function/

    说明

    在标准 C++,特别是当使用 C++ 标准程序库算法函数诸如 sortfind,用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicate function)。

    由于语言本身允许在函数内部定义类型,可以考虑使用函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程。此外,标准 C++ 不允许定义于函数内部的类型被用于模板,所以前述的作法是不可行的。

    C++11 对 lambda 的支持可以解决上述问题。

    一个 lambda 函数可以用如下的方式定义:

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

    指定返回类型

    这个不具名函数的回返类型是 decltype(x+y)。只有在 lambda 函数符合"return expression"的形式下,它的回返类型才能被忽略。在前述的情况下,lambda 函数仅能为一个述句。

    在一个更为复杂的例子中,回返类型可以被明确的指定如下:

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

    本例中,一个临时的参数 z 被创建用来存储中间结果。如同一般的函数,z 的值不会保留到下一次该不具名函数再次被调用时。

    如果 lambda 函数没有传回值(例如 void ),其回返类型可被完全忽略。

    定义在与 lambda 函数相同作用域的参数参考也可以被使用。这种的参数集合一般被称作 closure (闭包)。

    样式说明

    []          // 沒有定義任何變數。使用未定義變數會導致錯誤。
    [x, &y]     // x 以傳值方式傳入(預設),y 以傳參考方式傳入。
    [&]         // 任何被使用到的外部變數皆隱式地以參考方式加以引用。
    [=]         // 任何被使用到的外部變數皆隱式地以傳值方式加以引用。
    [&, x]      // x 顯示地以傳值方式加以引用。其餘變數以參考方式加以引用。
    [=, &z]     // z 顯示地以參考方式加以引用。其餘變數以傳值方式加以引用。
    

    closure 被定义与使用如下:

    std::vector<int> someList;
    int total = 0;
    std::for_each(someList.begin(), someList.end(), [&total](int x) {
      total += x;
    });
    std::cout << total;
    

    上例可计算 someList 元素的总和并将其印出。

    参数 total 是 lambda 函数 closure 的一部分,同时它以引用方式被传递入谓词函数, 因此它的值可被 lambda 函数改变。

    若不使用引用的符号&,则代表参数以传值的方式传入 lambda 函数。

    让用户可以用这种表示法明确区分参数传递的方法:传值,或是传参考

    由于 lambda 函数可以不在被声明的地方就地使用(如置入 std::function 对象中);

    这种情况下,若参数是以传参考的方式链接到 closure 中,是无意义甚至是危险的行为。

    若 lambda 函数只在定义的作用域使用, 则可以用 [&] 声明 lambda 函数, 代表所有引用到 stack 中的参数,都是以参考的方式传入, 不必一一显式指明:

    std::vector<int> someList;
    int total = 0;
    std::for_each(someList.begin(), someList.end(), [&](int x) {
      total += x;
    });
    

    参数传入 lambda 函数的方式可能随实做有所变化,一般期望的方法是 lambda 函数能保留其作用域函数的 stack 指针,借此访问区域参数。

    若使用 [=] 而非 [&],则代表所有的参考的参数都是传值使用。

    对于不同的参数,传值或传参考可以混和使用。 比方说,用户可以让所有的参数都以传参考的方式使用,但带有一个传值使用的参数:

    int total = 0;
    int value = 5;
    [&, value](int x) { total += (x * value); };
    

    total 是传参考的方式传入 lambda 函数,而 value 则是传值。

    若一个 lambda 函数被定义于某类型的成员函数中,会被当作该类型的 friend。像这样的 lambda 函数可以使用该类型对象的参考,并且能够访问其内部的成员。

    [](SomeType *typePtr) { typePtr->SomePrivateMemberFunction(); };
    

    这只有当该 lambda 函数创建的作用域是在 SomeType 的成员函数内部时才能运作。

    在成员函数中指涉对象的 this 指针,必须要显式的传入 lambda 函数, 否则成员函数中的 lambda 函数无法使用任何该对象的参数或函数。

    [this]() { this->SomePrivateMemberFunction(); };
    

    若是 lambda 函数使用 [&] 或是 [=] 的形式,this在 lambda 函数即为可见。

    lambda 函数是编译器从属类型的函数对象; 这种类型名称只有编译器自己能够使用。如果用户希望将 lambda 函数作为参数传入,该类型必须是模版类型,或是必须创建一个 std::function 去获取 lambda 的值。使用 auto 关键字让我们能够存储 lambda 函数:

    auto myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
    auto myOnheapLambdaFunc = new auto([=] { /*...*/ });
    

    但是,如果 lambda 函数是以参考的方式获取到它所有的 closure 参数,或者是没有 closure 参数,那么所产生的函数对象会被给予一个特殊的类型:std::reference_closure<R(P)>,其中 R(P) 是包含回返类型的函数签名。

    比起由 std::function 获取而来,这会是lambda函数更有效率的代表:

    std::reference_closure<void()> myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
    myLambdaFunc();
    
  • 相关阅读:
    CSS 兼容性调试技巧
    CSS 常用的兼容性调试技巧
    全局CSS设置
    CSS 盒子模型
    CSS表格属性
    HTML引入CSS的方法
    CSS 定位
    CSS display overflow 属性 cursor光标类型
    CSS 继承和优先级
    沟通表达
  • 原文地址:https://www.cnblogs.com/sollyu/p/4184523.html
Copyright © 2020-2023  润新知