tags:

views:

153

answers:

3
  class Action {
    public:
      void operator() () const;
  }

  class Data {
    public:
      Data();
      ~Data();
      Register(Action action) { _a = action; }

    private:
      Action _a;
   }

  class Display {
    public:
      Display(Data d) { d.Register( bind(Display::SomeTask, this, _1) ); }
      ~Display();
      void SomeTask();
  }

I want to bind the private member _a of Data to a member function of Display, but I get compile errors saying my argument types don't match when I call d.Register, what am I doing wrong? Thanks.

+1  A: 

I cannot see what 'bind' returns, but I absolutely sure this is not compatible with Action class. Also you are using 'copy semantic', so if Action has empty implmentation, you will never get desired. Try change Register(Action* action), and allow 'bind' to return some child of Action class.

Also review possibility to migrate to templates - than you even can exclude Action class at all

template <class A>
class Data { ...
Register(A action)...
A _a;
...

In this case you could be able to use as classes with overridden operator() as functions without argument.

Dewfy
+2  A: 

What you're trying to do is not completely clear, but I'll assume that "bind" is boost::bind (or tr1::bind).

A couple of problems with bind(Display::SomeTask, this, _1):

  • It should be &Display::SomeTask
  • The _1 placeholder makes no sense because that creates an unary function object and:
    • Display::SomeTask takes no arguments
    • Action::operator() takes no arguments

Using Boost.Function and Boost.Bind, here's what you could write to acheive what I guess you're trying to do:

typedef boost::function<void(void)> Action;

class Data {
public:
  Data();
  ~Data();
  Register(Action action) { _a = action; }

private:
  Action _a;
};

class Display {
public:
  Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
  ~Display();
  void SomeTask();
};
Éric Malenfant
A: 

First, you have to use &Display::SomeTask and give Register a return type, and then it depends on your needs

  • The wrapper should call SomeTask on *this: Omit _1.
  • The wrapper should call SomeTask on a passed Display object: Shift _1 in place of this.

Then, boost::bind returns some complicated synthesized type that will call the specified function. You need a way to store it, which is where boost::function comes handy. This is how you can do it

  class Display; // forward-declaration
  class Data {
    public:
      Data();
      ~Data();

      template<typename Action>
      void Register(Action action) { _a = action; }

    private:
      boost::function<void(Display&)> _a;
      // if wrapper should call it on `*this`
      // boost::function<void()> _a;
   }

  class Display {
    public:
      // this currently makes no sense. You pass a copy. Probably you
      // should consider pass-by-reference or processing "d" further. 
      Display(Data d) { d.Register( bind(&Display::SomeTask, _1) ); }
      // wrapper should call it on `*this`:
      // Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
      ~Display();
      void SomeTask();
  }

Then it should work.

Johannes Schaub - litb