C++中使用模板和Lambda表达式模拟std::function

C++编程中,经常需要存储和调用函数,包括那些带有捕获变量的Lambda表达式。标准库中的std::function提供了这样的功能,但有时候可能需要自定义的解决方案,或者出于某些原因不能使用标准库。本文将介绍如何使用C++11的特性,特别是模板和Lambda表达式,来模拟std::function的行为。

C++11引入了许多新特性,使得可以更灵活地处理函数和Lambda表达式。其中,变长模板参数和类型推导是实现自定义std::function的关键。通过这些特性,可以创建一个类,它能够存储任何匹配指定签名的Lambda表达式,包括那些捕获了变量的Lambda。

简单函数签名模板

类似于std::function,可以将函数的返回类型和参数类型作为模板参数传递。这种技术可以在StackOverflow上找到相关的讨论和标准参考。实现这一功能的步骤如下:

  1. 创建一个带有一个参数的模板类:
  2. template<typename T> class Lambda {};
  3. 使用简单函数签名语法对模板进行特化:
  4. template<typename Out, typename... In> class Lambda<Out(In...)> {};

使用这个模板类,可以获取Lambda表达式的返回类型和参数类型。例如:

Lambda<int(bool, int*)> "Out" 将被识别为 "int","In..." 将被识别为 "bool, int*"。

存储和管理Lambda函数指针

由于Lambda表达式可能捕获变量,不能简单地使用函数指针来存储Lambda。此外,由于Lambda表达式是独立的类,即使它们具有完全相同的规格,也不能使用auto关键字。因此,使用void指针来存储Lambda。

为了存储Lambda,需要复制Lambda并存储自己的副本,因为原始Lambda可能在使用类销毁之前就超出了作用域。以下是实现这一功能的代码示例:

template<typename LambdaType> Lambda<Out(In...)>& operator=(LambdaType const& lambda) { ... }

通过这种方式,可以存储Lambda表达式,但会丢失类型信息,无法删除或调用Lambda。为了解决这个问题,可以使用模板生成的Lambda函数来执行类型特定的操作。

完成代码

在展示最终的实用工具之前,需要指出的是,如果存储的Lambda的返回类型是void,上述的operator()将会失败。为了解决这个问题,将执行代码分离到一个单独的类中,并为void和非void返回类型提供不同的特化。

以下是完整的代码实现:

#include <cassert> // LambdaExecutor是内部类,增加了执行Lambda的能力。这个功能被分离出来,因为它是唯一需要特化(按返回类型)的部分。 template<typename T> class LambdaExecutor {}; template<typename Out, typename... In> class LambdaExecutor<Out(In...)> { public: Out operator()(In... in) { assert(lambda != nullptr); return executeLambda(lambda, in...); } protected: LambdaExecutor(void*& lambda) : lambda(lambda) {} ~LambdaExecutor() {} template<typename T> void generateExecutor(T const& lambda) { executeLambda = [](void* lambda, In... arguments) -> Out { return ((T*)lambda)->operator()(arguments...); }; } void receiveExecutor(LambdaExecutor<Out(In...)> const& other) { executeLambda = other.executeLambda; } private: void*& lambda; Out (*executeLambda)(void*, In...); }; template<typename... In> class LambdaExecutor<void(In...)> { public: void operator()(In... in) { assert(lambda != nullptr); executeLambda(lambda, in...); } protected: LambdaExecutor(void*& lambda) : lambda(lambda) {} ~LambdaExecutor() {} template<typename T> void generateExecutor(T const& lambda) { executeLambda = [](void* lambda, In... arguments) { ((T*)lambda)->operator()(arguments...); }; } void receiveExecutor(LambdaExecutor<void(In...)> const& other) { executeLambda = other.executeLambda; } private: void*& lambda; void (*executeLambda)(void*, In...); }; // Lambda包含大部分Lambda管理代码,可以直接在外部代码中使用。 template<typename T> class Lambda {}; template<typename Out, typename... In> class Lambda<Out(In...)> : public LambdaExecutor<Out(In...)> { public: Lambda() : LambdaExecutor<Out(In...)>(lambda), lambda(nullptr), deleteLambda(nullptr), copyLambda(nullptr) {} Lambda(Lambda<Out(In...)> const& other) : LambdaExecutor<Out(In...)>(lambda), lambda(other.copyLambda ? other.copyLambda(other.lambda) : nullptr), deleteLambda(other.deleteLambda), copyLambda(other.copyLambda) { receiveExecutor(other); } template<typename T> Lambda(T const& lambda) : LambdaExecutor<Out(In...)>(this->lambda), lambda(nullptr) { copy(lambda); } ~Lambda() { if (deleteLambda != nullptr) deleteLambda(lambda); } Lambda<Out(In...)>& operator=(Lambda<Out(In...)> const& other) { this->lambda = other.copyLambda ? other.copyLambda(other.lambda) : nullptr; receiveExecutor(other); this->deleteLambda = other.deleteLambda; this->copyLambda = other.copyLambda; return *this; } template<typename T> Lambda<Out(In...)>& operator=(T const& lambda) { copy(lambda); return *this; } operator bool() { return lambda != nullptr; } private: template<typename T> void copy(T const& lambda) { if (this->lambda != nullptr) deleteLambda(this->lambda); this->lambda = new T(lambda); generateExecutor(lambda); deleteLambda = [](void* lambda) { delete (T*)lambda; }; copyLambda = [](void* lambda) -> void* { return lambda ? new T(*(T*)lambda) : nullptr; }; } void* lambda; void (*deleteLambda)(void*); void* (*copyLambda)(void*); };

使用示例

Lambda<int(int)> storage = [](int a) { return a + 1; };
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485