std::function
is a tool useful to store any kind of callable object regardless of its type. In order to do this it needs to employ some type erasure technique, and that involves some overhead.
Any callable can be implicitly converted to a std::function
, and that's why it usually works seamlessly.
I'll repeat to make sure it becomes clear: std::function
is not something just for lambdas or function pointers: it's for any kind of callable. That includes things like struct some_callable { void operator()() {} };
, for example. That is a simple one, but it could be something like this instead:
struct some_polymorphic_callable {
template <typename T>
void operator()(T);
};
A lambda is just yet another callable object, similar to instances of the some_callable
object above. It can be stored in a std::function
because it's callable, but it doesn't have the type erasure overhead of std::function
.
And the committee plans to make lambdas polymorphic in the future, i.e., lambdas that look like some_polymorphic_callable
above. Which std::function
type would such a lambda be?
Now... Template parameter deduction, or implicit conversions. Pick one. That's a rule of C++ templates.
To pass a lambda as a std::function
argument, it needs to be implicitly converted. Taking a std::function
argument means that you're choosing implicit conversions over type deduction. But your function template needs the signature to be deduced or provided explicitly.
The solution? Don't restrict your callers to std::function
. Accept any kind of callable.
template <typename Fun>
auto flip(Fun&& f) -> decltype(std::bind(std::forward<Fun>(f),_2,_1))
{ return std::bind(std::forward<Fun>(f),_2,_1); }
You may now be thinking why do we need std::function
then. std::function
provides type erasure for callables with a known signature. That essentially makes it useful to store type-erased callables and to write virtual
interfaces.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…