windows C++-Lambda表达式(五)

在函数中使用 Lambda 表达式
示例

你可以在函数的主体中使用 lambda 表达式。 lambda 表达式可以访问该封闭函数可访问的任何函数或数据成员。 你可以显式或隐式捕获 this 指针,以提供对封闭类的函数和数据成员的访问路径。 Visual Studio 2017 版本 15.3 或更新版本(/std:c++17 及更新版本可用):在原始对象超出范围后,当可能会执行代码的异步或并行操作将使用 lambda 时,按值捕获 this ([*this])。

可以在函数中显式使用 this 指针,如下所示:

// capture "this" by reference
void ApplyScale(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [this](int n) { cout << n * _scale << endl; });
}

// capture "this" by value (Visual Studio 2017 version 15.3 and later)
void ApplyScale2(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [*this](int n) { cout << n * _scale << endl; });
}

你也可以隐式捕获 this 指针:

void ApplyScale(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [=](int n) { cout << n * _scale << endl; });
}

以下示例显示封装小数位数值的 Scale 类。 ApplyScale 函数使用 lambda 表达式打印小数位数值与 vector 对象中的每个元素的乘积。 lambda 表达式隐式捕获 this 指针,以便访问 _scale 成员。

// function_lambda_expression.cpp
// compile with: /EHsc /W4
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

class Scale
{
public:
    // The constructor.
    explicit Scale(int scale) : _scale(scale) {}

    // Prints the product of each element in a vector object
    // and the scale value to the console.
    void ApplyScale(const vector<int>& v) const
    {
        for_each(v.begin(), v.end(), [=](int n) { cout << n * _scale << endl; });
    }

private:
    int _scale;
};

int main()
{
    vector<int> values;
    values.push_back(1);
    values.push_back(2);
    values.push_back(3);
    values.push_back(4);

    // Create a Scale object that scales elements by 3 and apply
    // it to the vector object. doesn't modify the vector.
    Scale s(3);
    s.ApplyScale(values);
}

输出为:
3
6
9
12
配合使用 Lambda 表达式和模板
示例

由于 lambda 表达式已类型化,因此你可以将其与 C++ 模板一起使用。 下面的示例显示 negate_all 和 print_all 函数。 negate_all 函数将一元 operator- 应用于 vector 对象中的每个元素。 print_all 函数将 vector 对象中的每个元素打印到控制台。

// template_lambda_expression.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

// Negates each element in the vector object. Assumes signed data type.
template <typename T>
void negate_all(vector<T>& v)
{
    for_each(v.begin(), v.end(), [](T& n) { n = -n; });
}

// Prints to the console each element in the vector object.
template <typename T>
void print_all(const vector<T>& v)
{
    for_each(v.begin(), v.end(), [](const T& n) { cout << n << endl; });
}

int main()
{
    // Create a vector of signed integers with a few elements.
    vector<int> v;
    v.push_back(34);
    v.push_back(-43);
    v.push_back(56);

    print_all(v);
    negate_all(v);
    cout << "After negate_all():" << endl;
    print_all(v);
}

输出为:
34
-43
56
After negate_all():
-34
43
-56
处理异常
示例

lambda 表达式的主体遵循结构化异常处理 (SEH) 和 C++ 异常处理的原则。 你可以在 lambda 表达式主体中处理引发的异常或将异常处理推迟至封闭范围。 以下示例使用 for_each 函数和 lambda 表达式将一个 vector 对象的值填充到另一个中。 它使用 try/catch 块处理对第一个矢量的无效访问。

// eh_lambda_expression.cpp
// compile with: /EHsc /W4
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
    // Create a vector that contains 3 elements.
    vector<int> elements(3);

    // Create another vector that contains index values.
    vector<int> indices(3);
    indices[0] = 0;
    indices[-1] = 1; // This is not a valid subscript. It will trigger an exception.
    indices[2] = 2;

    // Use the values from the vector of index values to
    // fill the elements vector. This example uses a
    // try/catch block to handle invalid access to the
    // elements vector.
    try
    {
        for_each(indices.begin(), indices.end(), [&](int index) {
            elements.at(index) = index;
        });
    }
    catch (const out_of_range& e)
    {
        cerr << "Caught '" << e.what() << "'." << endl;
    };
}

输出为:
Caught 'invalid vector<T> subscript'.
配合使用 Lambda 表达式和托管类型 (C++/CLI)
示例

lambda 表达式的捕获子句不能包含具有托管类型的变量。 但是,你可以将具有托管类型的实际参数传递到 lambda 表达式的形式参数列表。 以下示例包含一个 lambda 表达式,它通过值捕获局部非托管变量 ch,并采用 System.String 对象作为其参数。

// managed_lambda_expression.cpp
// compile with: /clr
using namespace System;

int main()
{
    char ch = '!'; // a local unmanaged variable

    // The following lambda expression captures local variables
    // by value and takes a managed String object as its parameter.
    [=](String ^s) {
        Console::WriteLine(s + Convert::ToChar(ch));
    }("Hello");
}

输出为:
Hello!

以下公共语言运行时 (CLR) 托管实体中不支持 Lambda:

ref class、ref struct、value class 以及 value struct;

C++ 中的 constexpr lambda 表达式

Visual Studio 2017 版本 15.3 及更高版本 (在 /std:c++17 模式和更高版本中可用):在常量表达式中允许初始化捕获或引入的每个数据成员时,可以将 lambda 表达式声明为 constexpr,或在常量表达式中使用它。

    int y = 32;
    auto answer = [y]() constexpr
    {
        int x = 10;
        return y + x;
    };

    constexpr int Increment(int n)
    {
        return [n] { return n + 1; }();
    }

如果 Lambda 结果满足 constexpr 函数的要求,则 Lambda 是隐式的 constexpr:

    auto answer = [](int n)
    {
        return 32 + n;
    };

    constexpr int response = answer(10);

如果 lambda 是隐式或显式的 constexpr,并且将其转换为函数指针,则生成的函数也是 constexpr:

    auto Increment = [](int n)
    {
        return n + 1;
    };

    constexpr int(*inc)(int) = Increment;
相关推荐
2401_857439691 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna2 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
Dream_Snowar3 小时前
速通Python 第三节
开发语言·python
唐诺3 小时前
几种广泛使用的 C++ 编译器
c++·编译器
高山我梦口香糖4 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
冷眼看人间恩怨4 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
信号处理学渣4 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客4 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin4 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin