C++新特性lambda

#include <iostream>
#include <memory>  // std::make_unique
#include <utility> // std::move
#include <functional>

/*lambda表达式是匿名函数,本质是一个仿函数(可调用对象)
[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}
捕获列表:[] 代表空捕获列表
         [name_var1, name_var2, ...] 捕获指定变量(值捕获),函数体中可以读取(值拷贝)
         [&] 引用捕获,让编译器自动推导引用列表,函数体中可以进行修改(引用捕获,可以修改)
         [=] 值捕获,让编译器自动推导值捕获列表,函数体中可以进行读取(值拷贝)
         [this] 可以捕获类对象成员
        注意:上面捕获都是捕获外部作用域声明的变量,捕获的只能时左值(有对应的内存地址),而不能捕获右值


*/

// 值捕获
void Test1()
{
    int a = 1;
    int b = 2;
    // 返回可调用对象
    auto func = [a]()
    {
        int c = a;
        // int d = b; error 捕获列表中只值捕获a
        return a; // 捕获value
    };
    std::cout << func() << std::endl; // 1;

    // 使用仿函数直接调用, 可以捕获所以变量,值拷贝,不能修改
    [=](int value)
    {
        int c = a; // a and b read only
        int d = b;
        std::cout << value << std::endl; // expect 3
    }(3);                                // 后面加上()会立即调用(仿函数)

    // 修改可读值
    [a](int value) mutable
    {
        a = 20; // 加上可选关键字mutalbe后,可以修改只读变量,但因为是值传递,外面a变量不会被修改
        return value;
    }(20);
    std::cout << a << std::endl; // expect 1
	//	若对func可调用对象,值捕获列表值一直都是func对象生成时就绑定好了(常量)
	// 不会因为捕获列表值发生变化,再次调用对象而结果不同
	a++;
	func();// expect 1
}

// 引用捕获
void Test2()
{
    int a = 1;
    int b = 2;
    // 只引用捕获a变量
    auto func = [&a]()
    {
        return ++a; // 引用捕获a并修改,外部实际值被修改
    };
    std::cout << a << std::endl; // expect 2;

    // 引用捕获外面所有变量
    [&](int value)
    {
        a++;
        b++;
        return value;
    }(20);
    std::cout << a << "," << b << std::endl; // expect 3,2
}

// lamdba表达式只有捕获列表为空时才能作为函数指针
void Test3()
{
    using FuncType = void (*)(int, int);
    FuncType func = [](int l, int r)
    {
        std::cout << l << "," << r << std::endl;
    };
    func(1, 1); // lambda无捕获参数时作为函数指针

    // FuncType func1 = [=](int l, int r)
    // {
    //     std::cout << l << "," << r << std::endl;
    // };// error,捕获列表不为空时,不可以作为函数指针

    // 解决1.function包装器包装可调用对象
    std::function<void(int, int)> func1 = [=](int l, int r)
    {
        std::cout << l << "," << r << std::endl;
    };
    func1(2, 2);

    // 解决2.使用bind绑定器返回一个仿函数对象
    auto func2 = std::bind([=](int l, int r)
                           { std::cout << l << "," << r << std::endl; },
                           3, std::placeholders::_2);
    func2(10, 3); // 3, 3
}

// C++14 给与了我们方便,允许捕获的成员用任意的表达式进行初始化,这就允许了右值的捕获,
//  被声明的捕获变量类型会根据表达式进行判断,判断方式与使用 auto 本质上是相同的
void lambda_expression_capture()
{
    auto important = std::make_unique<int>(1);
    auto add = [v1 = 2, v2 = std::move(important)](int x, int y) -> int
    {
        return x + y + v1 + (*v2);
    };
    std::cout << add(3, 4) << std::endl; // 3 + 4 + 2 + 1
}

// 泛型lambda, c14开始之初泛型
auto fun = [](auto x, auto y){ return x+y;}
int main()
{
    Test3();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值