1

I remember vaguely that python allowed something like

def foo( x ):
    ....

f = foo( 5 )

Is something like that possible in c++ so that if I have a member function

class C {

    void foo( int x ) { ... }

so that I can define a pointer or variable that would effectively point at foo( 5 )

The reason why I want to do this is because I have many listeners that I need to subscribe to a callback and keep information who gets called

class C {
     map<int, ptrSender> m_sender;

    void subscribe() {
        for (const auto& p : m_sender) {
            p .second->register( Callback( this, &C::onCall ) )
        }

My problem is that the onCall does not return which sender called back, but I would need this information. So, instead of doing something like this

    void subscribe() {
         m_sender[0]->register( Callback( this, onCall_0 ) );
         m_sender[1]->register( Callback( this, onCall_1 ) );
         ....

   void onCall( int sender_id ) { ... }
   void onCall_0() { onCall( 0 ); }
   void onCall_1() { onCall( 1 ); }
   ....

I was hoping I could pass something into register that would return a call with a preset argument. Is this possible?

EDIT: I am trying to use a lambda function, but I am running into the following problems

auto setCall= [this]( int v ) { &C::onCall( v ); }

gives the compile error

lvalue required as unary&opeand

This

auto setCall= [this]( int v ) { C::onCall( v ); }
.... 
p.second->register( Callback( this, &setCall( p.first) ) );   /// <__ error now here

complains again, now in the second line

lvalue required as unary&operand

and this

auto setCall= [this]( int v ) { C::onCall( v ); }
.... 
p.second->register( Callback( this, setCall( p.first) ) );   /// <__ error now here

complains about invalid use of void expression, but I assume I have to pass in a reference to make the register function happy

Callback seems to be defined as

#  define CallBack(obj,func) ProfiledBasicCallBack(obj,fastdelegate::FastDelegate0<void>(obj,func),#func)
chrise
  • 3,415
  • 2
  • 21
  • 58
  • 2
    Possible duplicate of [What is a lambda expression in C++11?](http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11) – kay Dec 14 '16 at 03:30
  • 3
    Looks like you want to use bind: http://stackoverflow.com/questions/6610046/stdfunction-and-stdbind-what-are-they-when-they-should-be-used – Michael Albers Dec 14 '16 at 03:32
  • That bind looks promising, let me try that – chrise Dec 14 '16 at 03:34
  • If you can prefer a lambda over bind. – Paul Rooney Dec 14 '16 at 03:44
  • What is the parameter types of your `register` function? The second parameter specifically. – AnT Dec 14 '16 at 04:12
  • I edited the text. actually there is a callback function passed into teh register function. I dont understand what creature that is, though – chrise Dec 14 '16 at 04:21

3 Answers3

5

Yes, you can use std::bind. Example usage: http://ideone.com/akoWbA.

void foo( int x ) { cout << x << endl; }
auto x = std::bind(foo, 5);
x();

However, with modern C++, you should use a lambda. Like so:

void foo( int x ) { cout << x << endl; }
auto x = []() { foo(5); };
x();

Note that this foo function is outside of the class C in this example. If you wish to contain it inside, then with std::bind you need to pass the instance of the object you wish to call on, e.g.

C c;
auto x = std::bind(&C::foo, &c, 5);
x();

or with lambdas:

C c;
auto x = [&c]() { c.foo(5); };
x();
miguel.martin
  • 1,546
  • 10
  • 26
  • @smac89 Thanks, my bad. – miguel.martin Dec 14 '16 at 04:34
  • if you have std::bind available, you will have lambdas. They appeared in the same standard release. In c++11 there were a few use cases for bind, but it was mostly already an anachronism. As of c++14, there is no case in which bind is a better tool than a lambda. Use lambdas. – Richard Hodges Dec 14 '16 at 08:09
2

What you are looking for is std::bind(). It takes one callable object, and gives you another callable object with predefined values for its parameter, and maybe some optional parameters forwarded to it.

A word of warning: this is a fairly steep learning curve. You need to understand templates.

Sam Varshavchik
  • 84,126
  • 5
  • 57
  • 106
  • 1
    I would never recommend std::bind over a lambda function. It's far more difficult to understand, and with `[&](){}` you have a much easier control what you need to copy, and what you can simply reference. – kay Dec 14 '16 at 03:46
2

If you want to bind a parameter value to a compile-time constant argument (like 5 in your example), then the problem can be solved by introducing a simple wrapper function that will call your function while passing the desired constant values as corresponding arguments.

But when the argument is a run-time value, then the answer is no: it is generally not possible to create a credible implementation of such function pointer binding in C++ (unless you are using some compiler-specific extension).

However, in C++ you have a variety of alternative tools at your disposal. You can create a function object that will mimic the functionality you desire. Such function object can be created by using std::bind, by using lambda-expressions, or even implemented manually.

The resultant function object will be "callable" and will behave similarly to function pointer at superficial level, but nevertheless it won't be a function pointer, won't be convertible to a function pointer and won't be accepted where a genuine function pointer is required. In other words, if your register method is declared to expect a function pointer as its second argument, then there's nothing you can do here. Neither std::bind, nor lambdas, nor anything else in the language will help you to achieve this kind of parameter binding.

For this reason it is generally a good idea to steer clear of function pointers in such designs and implement such functionality in terms of generic callable objects. The simplest thing to use might be std::function objects in place of raw function pointers.

AnT
  • 291,388
  • 39
  • 487
  • 734