简体   繁体   中英

std::bind and std::function questions

int func(int x){return x;}
...
std::function<int(int)> x = std::bind(func, std::placeholders::_1);
x(123);
  1. 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) ?
  2. Where does the functor live which std::bind generates? In what scope? And how does std::bind name it? (can there be name collisions)
  3. Can lambdas replace all uses of std::bind ?
  4. Is std::bind as optimal as implementing it as a lambda instead?
  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?

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

1 . 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) ?

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 does std::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 (ie 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
 {
     // ..
 }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM