C++11 lambda 表达式

C++11 引入了 lambda 表达式,这是一种定义匿名函数的简便方式。它允许你定义匿名的内联函数对象。这些函数对象可以捕获其所在作用域中的变量,并且可以用于需要函数对象的任何地方,如算法或函数回调。Lambda 表达式特别适用于需要一个函数对象,但该函数对象只会被调用一次的情况。Lambda 表达式的基本语法如下:

[capture](parameters) -> return_type { body }
  • [capture]:捕获子句,用于捕获 lambda 函数体外的变量。
  • (parameters):参数列表,与普通函数的参数列表相同。
  • -> return_type:返回类型,当 lambda 函数体只有一条返回语句时可以省略。
  • { body }:函数体,即 lambda 函数要执行的代码。

在捕获子句中,可以使用不同的捕获方式:

  • []:不捕获任何外部变量。
  • [=]:以值捕获所有外部变量(变量会被复制)。
  • [&]:以引用捕获所有外部变量(变量不会被复制)。
  • [var]:以值捕获指定的外部变量 var
  • [&var]:以引用捕获指定的外部变量 var
  • [=, &var][var, &...]:混合捕获方式,首先以值捕获所有外部变量,但指定的变量 var 以引用捕获,或者先以值捕获除 var 外的所有外部变量,然后 var 以引用捕获,等等。

示例代码

示例 1:无参数、无返回值、无捕获的 lambda
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    std::for_each(nums.begin(), nums.end(), [](int n) {
        std::cout << n << std::endl;
    });
    return 0;
}
示例 2:有参数、有返回值、无捕获的 lambda
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {1, 4, 9, 16, 25};
    int sum = std::accumulate(nums.begin(), nums.end(), 0, [](int a, int b) {
        return a + b * b; // 假设这里我们对每个元素平方后再求和
    });
    std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 55 (1 + 16 + 81 + 256 + 625)
    return 0;
}
示例 3:有参数、有返回值、有捕获的 lambda
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int x = 10;
    std::vector<int> nums = {1, 2, 3, 4, 5};
    std::transform(nums.begin(), nums.end(), nums.begin(), [x](int n) {
        return n * x; // 使用捕获的变量 x 来乘以每个元素
    });
    for (int num : nums) {
        std::cout << num << " "; // 输出: 10 20 30 40 50
    }
    return 0;
}

使用

在C++11中,Lambda 表达式经常用于实现回调函数和消息机制。下面我将给出两个简单的示例来说明这一点。

示例 1:Lambda 表达式作为回调函数

假设我们有一个函数,它接受一个回调函数作为参数,并在某个条件满足时调用这个回调函数。

#include <iostream>
#include <functional>

// 假设的函数,接受一个回调函数
void processData(const std::string& data, std::function<void(const std::string&)> callback) {
    // 模拟数据处理过程
    // ...

    // 假设处理完成,调用回调函数
    callback(data);
}

int main() {
    // 使用 Lambda 表达式作为回调函数
    processData("Hello, World!", [](const std::string& result) {
        std::cout << "Processing complete: " << result << std::endl;
    });

    return 0;
}

在这个示例中,processData 函数接受一个 std::function<void(const std::string&)> 类型的回调函数作为参数。我们使用一个 Lambda 表达式来定义这个回调函数,并在 processData 函数内部调用它。

示例 2:Lambda 表达式用于消息机制

假设我们有一个简单的消息队列,它允许注册回调函数来处理不同类型的消息。

#include <iostream>
#include <functional>
#include <map>
#include <string>

class MessageQueue {
public:
    // 注册消息处理函数
    void registerMessageHandler(const std::string& messageType, std::function<void(const std::string&)> handler) {
        handlers_[messageType] = handler;
    }

    // 发送消息并调用相应的处理函数
    void sendMessage(const std::string& messageType, const std::string& message) {
        auto it = handlers_.find(messageType);
        if (it != handlers_.end()) {
            it->second(message);
        } else {
            std::cout << "No handler registered for message type: " << messageType << std::endl;
        }
    }

private:
    std::map<std::string, std::function<void(const std::string&)>> handlers_;
};

int main() {
    MessageQueue queue;

    // 注册消息处理函数
    queue.registerMessageHandler("greeting", [](const std::string& message) {
        std::cout << "Received greeting: " << message << std::endl;
    });

    // 发送消息
    queue.sendMessage("greeting", "Hello from the message queue!");

    return 0;
}

在这个示例中,我们定义了一个 MessageQueue 类,它使用一个 std::map 来存储消息类型和相应的处理函数。我们使用 Lambda 表达式来定义处理函数,并通过 registerMessageHandler 方法将它们注册到消息队列中。然后,当我们发送消息时,消息队列会查找相应的处理函数并调用它。

std::function是C++11标准中引入的一个模板类,专门用于封装可调用对象,例如普通函数、lambda表达式、仿函数等。它的主要目的是提供一个统一的函数对象包装器,能够存储、复制和调用任何可调用目标。

下面将详细探讨std::function的具体用法和内部机制,并提供代码示例:

  1. 基本概念与引入

    • 定义与头文件:std::function是定义在<functional>头文件中的模板类。
    • 目的与用途:它的主要目的是提供一个统一的函数对象包装器,能够存储、复制和调用任何可调用目标。
  2. 可调用对象类型

    • 普通函数:可以封装普通函数,例如一个简单的加减法函数。
    • Lambda表达式:可以封装Lambda表达式,提供匿名函数功能。
    • 仿函数:可以封装仿函数,即那些重载了operator()的类。
    • 类成员函数指针:可以封装类成员函数指针,使得对象方法可以被像普通函数一样调用。
    • 数据成员访问器:可以封装对类的数据成员的访问器。
  3. 使用方法与示例

    • 封装普通函数:可以用std::function来封装定义好的普通函数。
    • 封装Lambda表达式:可以封装lambda表达式,实现代码的灵活复用。
    • 绑定复杂表达式:通过std::bind,可以将复杂的函数调用绑定为简单的函数对象。
  4. 内部机制与类型擦除

    • 模板和多态:std::function的内部实现依赖于模板和多态性。通过模板参数推导和类型擦除技术,将各种类型的可调用对象转换成一个通用的内部结构体对象。
    • 异常安全性:当std::function实例不包含目标时,调用它会抛出std::bad_function_call异常。
  5. 高级应用与注意事项

    • 实现观察者模式:可以利用std::function来实现观察者设计模式,提高代码的可扩展性和可维护性。
    • 作为函数参数或返回值:std::function可以作为其他函数的参数或返回值,实现高阶函数的功能。
    • 性能考虑:虽然std::function提供了很多便利,但类型擦除可能会带来一定的性能开销,需要在关注性能的场景下谨慎使用。

下面是一些代码示例:

#include <iostream>
#include <functional>

// 普通函数示例
int add(int a, int b) {
    return a + b;
}

// Lambda表达式示例
auto multiply = [](int a, int b) { return a * b; };

// 仿函数示例
struct divide {
    int operator()(int a, int b) const {
        return a / b;
    }
};

// 类成员函数指针示例
class MyClass {
public:
    int subtract(int a, int b) {
        return a - b;
    }
};

// 数据成员访问器示例
struct Point {
    int x;
    int y;
    int getX() const { return x; }
    int getY() const { return y; }
};

int main() {
    // 封装普通函数
    std::function<int(int, int)> func1 = add;
    std::cout << "add(3, 4) = " << func1(3, 4) << std::endl; // 输出:add(3, 4) = 7

    // 封装Lambda表达式
    std::function<int(int, int)> func2 = multiply;
    std::cout << "multiply(3, 4) = " << func2(3, 4) << std::endl; // 输出:multiply(3, 4) = 12

    // 封装仿函数
    std::function<int(int, int)> func3 = divide();
    std::cout << "divide(8, 4) = " << func3(8, 4) << std::endl; // 输出:divide(8, 4) = 2

    // 封装类成员函数指针
    MyClass obj;
    std::function<int(int, int)> func4 = std::bind(&MyClass::subtract, &obj, std::placeholders::_1, std::placeholders::_2);
    std::cout << "obj.subtract(7, 4) = " << func4(7, 4) << std::endl; // 输出:obj.subtract(7, 4) = 3

    // 封装数据成员访问器
    Point p{3, 4};
    std::function<int()> func5 = std::bind(&Point::getX, &p);
    std::cout << "p.getX() = " << func5() << std::endl; // 输出:p.getX() = 3

    return 0;
}

综上所述,std::function是一个非常强大的工具,它不仅能够简化代码、提升可读性和可维护性,还能以统一的方式处理多种类型的可调用对象。通过合理地使用std::function,可以在现代C++编程中充分利用函数式编程的特性,提高软件的质量和效率。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值