Reputation: 28178
int func(int x){return x;}
...
std::function<int(int)> x = std::bind(func, std::placeholders::_1);
x(123);
x(123)
actually call the operator()
of the functor which std::function
generated which in turn calls the operator()
of the functor which std::bind
generated which finally calls func
? Does this get optimized into something as optimal as calling func(123)
?std::bind
generates? In what scope? And how does std::bind
name it? (can there be name collisions)std::bind
?std::bind
as optimal as implementing it as a lambda instead?std::function
? How does that get parsed and how can I use that template argument syntax elsewhere?Upvotes: 11
Views: 3735
Reputation: 1
Can lambdas replace all uses of std::bind?
C++14 will allow lambdas to mostly replace bind. Responding in particular to Luc Danton's answer, in C++14, you can write templated lambdas using auto such that bound(0)
and bound(0L)
behave differently.
Upvotes: 0
Reputation: 392863
1 . Does
x(123)
actually call theoperator()
of the functor whichstd::function
generated which in turn calls theoperator()
of the functor whichstd::bind
generated which finally callsfunc
? Does this get optimized into something as optimal as callingfunc(123)
?
If you have optimizations enabled, the 'stuff' gets inlined and you can count on this being as optimal as calling func(123)
.
2 . Where does the functor live which
std::bind
generates? In what scope? And how doesstd::bind
name it? (can there be name collisions)
Precising: bind
generates a 'fleeting', implementation defined, bind expression, that is assignable to function<>
. Function is just a class template (Thanks, Luc T.). And it lives in the standard library. However, the bind expressions are implementation defined.
The standard library does come with traits (std::is_bind_expression<>
) to allow MPL detection of such expressions. One decisive feature of bind expressions over std::function is that they are (what I'd call) deferred callable objects (i.e. that they retain full call site semantics including the ability to select overloads at the actual application site). std::function<>
, on the other hand, commits to a single prototype and internally stores the callable object by type erasure (think variant
or any
).
3 . Can lambdas replace all uses of std::bind?
4 . Is std::bind as optimal as implementing it as a lambda instead?
AFAICT lambdas should compile down to about the same as the bind expressions. One thing that I think lambdas can't do that bind expressions can is nested bind expressions
Edit While the specific idiom of nested bind expressions is not replicatable using lambdas, lambdas are of course able to express (nearly) the same much more naturally:
bind(f, bind(g, _1))(x);
// vs.
[](int x) { f(g(x)); };
5 . What's up with the syntax of the template argument of
std::function
? How does that get parsed and how can I use that template argument syntax elsewhere?
It is just a function signature (the type of a function), being passed as template parameter.
You can also use it as a function parameter type, which degrades to a function pointer(similar to how array by-value parameters degrade to pointers, Thanks David!). In practice, most anywhere, as long as you don't have a need to name a variable/type:
void receiveFunction(void(int, double)); // spunky 'function<>'-style syntax
void sample(int, double) { }
int main()
{
receiveFunction(sample);
}
void receiveFunction(void (*f)(int, double)) // boring 'old' style syntax
// void ( f)(int, double) // ... also ok
{
// ..
}
Upvotes: 6
Reputation: 35449
Does x(123) actually call the operator() of the functor which std::function generated which in turn calls the operator() of the functor which std::bind generated which finally calls func? Does this get optimized into something as optimal as calling func(123)?
I wouldn't describe the operator()
of std::function
as 'generated' (it's a regular member), but otherwise that is a good description. Optimizations are up to your compiler, but be warned that to optimize the indirection of std::function
(which requires the use of type erasure) a compiler may need to perform heroics.
Where does the functor live which std::bind generates? In what scope? And how does std::bind name it? (can there be name collisions)
The call to std::bind
returns a functor of unspecified type, and a copy of that functor is stored inside the x
object. This copy will live as long as x
itself. There is no name involved so I'm not sure what you mean by that.
Can lambdas replace all uses of std::bind?
No. Consider auto bound = std::bind(functor, _1);
where functor
is a type with an overloaded operator()
, let's say on long
and int
. Then bound(0L)
doesn't have the same effect as bound(0)
and you can't replicate that with a lambda.
Is std::bind as optimal as implementing it as a lambda instead?
This is up to the compiler. Measure yourself.
What's up with the syntax of the template argument of std::function? How does that get parsed and how can I use that template argument syntax elsewhere?
It's a function type. Perhaps you're already familiar with the syntax for pointers/references to functions: void(*)()
, int(&)(double)
. Then just remove the pointer/reference out of the type, and you just have a function type: void()
, int(double)
. You can use those like so:
typedef int* function_type(long);
function_type* p; // pointer to function
Upvotes: 16