在C++编程中,经常需要存储和调用函数,包括那些带有捕获变量的Lambda表达式。标准库中的std::function
提供了这样的功能,但有时候可能需要自定义的解决方案,或者出于某些原因不能使用标准库。本文将介绍如何使用C++11的特性,特别是模板和Lambda表达式,来模拟std::function
的行为。
C++11引入了许多新特性,使得可以更灵活地处理函数和Lambda表达式。其中,变长模板参数和类型推导是实现自定义std::function
的关键。通过这些特性,可以创建一个类,它能够存储任何匹配指定签名的Lambda表达式,包括那些捕获了变量的Lambda。
类似于std::function
,可以将函数的返回类型和参数类型作为模板参数传递。这种技术可以在StackOverflow上找到相关的讨论和标准参考。实现这一功能的步骤如下:
template<typename T> class Lambda {};
template<typename Out, typename... In> class Lambda<Out(In...)> {};
使用这个模板类,可以获取Lambda表达式的返回类型和参数类型。例如:
Lambda<int(bool, int*)> "Out" 将被识别为 "int","In..." 将被识别为 "bool, int*"。
由于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; };