0

std::function can wrap lambdas with capture list but how std::function implemented? We don't know what is the type of it, it can be assigned to void* but then it is not possible to call lambda

Kanony
  • 509
  • 2
  • 12

1 Answers1

1

Disclaimer: this is incomplete, possibly incorrect and doesn't follow std::function api and conventions (e.g. it is not copyable). This is just an example to show one way of how the type erasure of a std::function like type can be implemented, striped down to the bare minimum to understand the type erasure technique.

In order to store any type and be able to call it according to a function signature we use polymorphism.

This is the base abstract class for a Signature that defines the calling API. Signature must be a function type:

template <class Signature> struct CallableBase;

template <class R, class... Args>
struct CallableBase<R(Args...)>
{
    virtual R call(Args... args) = 0;
};

Next we need a derived class that holds the actual callable object F and can call it:

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...);
    }
};

In our Function class we hold a pointer of type CallableBase to an object of type Callable<F> to enable polymorphism and get the desired behavior:

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...);
    }
};

And this gets us a basic type erased Function:

auto test()
{
    int x = 10;

    Func<int(int, int)> f = [=] (int a, int b) { return a * x + b; };

    return f(2, 5); // 25
}
bolov
  • 72,283
  • 15
  • 145
  • 224