Explanation of std::function

  • A+
Category:Languages

What is the purpose of std::function? As far as I understand, std::function turns a function, functor, or lambda into a function object.

I don't quite understand the purpose of this... Both Lambdas and Functors are function objects already and I do believe that they can be used as predicates for algorithms like sort and transform. As a side note, Lambdas are actually Functors (internally). So the only thing I can see std::function being useful for is to turn regular functions into function objects.

And I don't quite see why I would want to turn a regular function into a function object either. If I wanted to use a function object I would have made one in the first place as a functor or lambda... rather than code a function and then convert it with std::function and then pass it in as predicate...

I'm guessing that there is much more to std::function... something that isn't quite obvious at first glance.

An explanation of std::function would be much appreciated.

 


What is the purpose of std::function? As far as I understand, std::function turns a function, functor, or lambda into a function object.

std::function is an example of a broader concept called Type Erasure. The description you have isn't quite accurate. What std::function<void()> does, to pick a specific specialization, is represent any callable that can be invoked with no arguments. It could be a function pointer or a function object that has a concrete type, or a closure built from a lambda. It doesn't matter what the source type is, as long as it fits the contract - it just works. Instead of using the concrete source type, we "erase" it - and we just deal with std::function.

Now, why would we ever use type erasure? After all, don't we have templates so that we can use the concrete types directly? And wouldn't that be more efficient and isn't C++ all about efficiency?!

Sometimes, you cannot use the concrete types. An example that might be more familiar is regular object-oriented polymorphism. Why would we ever store a Base* when we could instead store a Derived*? Well, maybe we can't store a Derived*. Maybe we have lots of different Derived*s that different users use. Maybe we're writing a library that doesn't even know about Derived. This is also type erasure, just a different technique for it than the one std::function uses.

A non-exhaust list of use-cases:

  • Need to store a potentially heterogenous list of objects, when we only care about them satisfying a concrete interface. For std::function, maybe I just have a std::vector<std::function<void()>> callbacks - which might all have different concrete types, but I don't care, I just need to call them.
  • Need to use across an API boundary (e.g. I can have a virtual function taking a std::function<void()>, but I can't have a virtual function template).
  • Returning from a factory function - we just need some object that satisfies some concept, we don't need a concrete thing (again, quite common in OO polymorphism, which is also type erasure).
  • Could potentially actually use templates everywhere, but the performance gain isn't worth the compilation hit.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: