【发布时间】:2021-04-12 21:39:46
【问题描述】:
std::function 可以用捕获列表包装 lambda,但 std::function 是如何实现的?我们不知道它是什么类型的,可以赋值给void*但是之后就不能调用lambda了
【问题讨论】:
-
你看过 libstdc++ 和 libc++ 中的实现吗?
-
@StephenNewell 图书馆就是一团糟
std::function 可以用捕获列表包装 lambda,但 std::function 是如何实现的?我们不知道它是什么类型的,可以赋值给void*但是之后就不能调用lambda了
【问题讨论】:
免责声明:这是不完整的,可能不正确,并且不遵循 std::function api 和约定(例如,它不可复制)。这只是一个示例,展示了如何实现 std::function 类似类型的类型擦除的一种方法,将其精简到最低限度以了解类型擦除技术。
为了存储任何类型并能够根据函数签名调用它,我们使用了多态性。
这是定义调用 API 的 Signature 的基本抽象类。 Signature 必须是函数类型:
template <class Signature> struct CallableBase;
template <class R, class... Args>
struct CallableBase<R(Args...)>
{
virtual R call(Args... args) = 0;
};
接下来我们需要一个派生类来保存实际的可调用对象F 并可以调用它:
template <class F, class Signature> struct Callable;
template <class F, class R, class... Args>
struct Callable<F, R(Args...)> : CallableBase<R(Args...)>
{
F f;
Callable(F f) : f{f} {}
R call(Args... args) override
{
return f(args...);
}
};
在我们的Function 类中,我们持有一个CallableBase 类型的指针,指向Callable<F> 类型的对象,以启用多态性并获得所需的行为:
template <class Signature> struct Func;
template <class R, class... Args>
struct Func<R(Args...)>
{
using Signature = R(Args...);
std::unique_ptr<CallableBase<Signature>> callable_;
template <class F>
Func(F f) : callable_{std::make_unique<Callable<F, Signature>>(f)} {}
R operator()(Args... args)
{
return callable_->call(args...);
}
};
这让我们得到了一个基本类型被删除Function:
auto test()
{
int x = 10;
Func<int(int, int)> f = [=] (int a, int b) { return a * x + b; };
return f(2, 5); // 25
}
【讨论】: