0

Consider the snippet:

# include <iostream>

# include <boost/scoped_ptr.hpp>
# include <boost/shared_ptr.hpp>

# include <boost/function.hpp>
# include <boost/array.hpp>
# include <boost/asio.hpp>
# include <boost/thread.hpp>
# include <boost/thread/locks.hpp>
# include <boost/bind.hpp>
# include <boost/noncopyable.hpp>

# include <boost/variant.hpp>


class DataLink {};
class Metadata {};
class Image {};

 typedef boost::function<void( DataLink const&, Metadata const& , Image const& )> Handler ; 
 typedef boost::function<void( Metadata const& , Image const& )> Handler2 ; 
 typedef boost::function<void( Image const& )> Handler3 ; 

typedef boost::variant<DataLink, Metadata, Image> Variant; 



enum callbackHandler { link_enum, meta_enum, image_enum };
class Worker {
  Handler  callBack ;
  //Handler2 callBack2 ;
  //Handler3 callBack3 ;

  DataLink dlink;
  Metadata meta ;
  Image    img ;

  callbackHandler handlerEnum ;

public :
  Worker ( const Handler& handler ) 
  : callBack ( handler ) 
   {}
  //Worker ( const Handler2& handler ) 
  //: callBack2 ( handler ) 
  // {}
  //Worker ( const Handler3& handler ) 
  //: callBack3 ( handler ) 
  // {}

  void Image ( ) {
    // update the img object 
    // invoke call back 
    handlerEnum = image_enum ;
    //const std::type_info& xxx = callBack.target_type();
    //std::cout << xxx.raw_name() << std::endl;
    callBack ( dlink, meta, img ) ;
  }

  void Metadata ( ) {
    // update the meta object 
    // invoke call back 
    handlerEnum = meta_enum ;
    callBack ( dlink, meta, img ) ;
  }

  void Dlink ( ) {
    // update the link object 
    // invoke call back 
    handlerEnum = link_enum ;
    callBack ( dlink, meta, img ) ;
  }

  callbackHandler getHandlerType() { return handlerEnum ; }
};

class Foo {
  Worker *ptrWorker ;
public :
  Foo () 
  : ptrWorker( 0 ) 
  {}

  void callback ( DataLink const& d, Metadata const& m , Image const&  i ) {
    callbackHandler tt = ptrWorker->getHandlerType();
    if ( tt == image_enum ) {
      std::cout <<  "Image object " << std::endl;
    }
    if ( tt == meta_enum ) {
      std::cout <<  "Meta object " << std::endl;
    }
    if ( tt == link_enum ) {
      std::cout <<  "Link object " << std::endl;
    }

  }
  bool start () {
    ptrWorker = new ( std::nothrow ) Worker ( boost::bind ( &Foo::callback, this, _1, _2, _3 ) );
    if ( !ptrWorker ) {
      return - 1 ;
    }
  }
  void testWorker() {
    ptrWorker->Image() ;
    ptrWorker->Metadata() ;
    ptrWorker->Dlink() ;
  }
};

int main() {
  Foo f;
  f.start() ;
  f.testWorker() ;
  std::cin.get() ;
}

The commented out constructors allows me to add support for Handler2 and Handler3, however is there a way to determine the handler that was passed to the constructor of the Worker class? At present the member functions Metadata, Image and Dlink use the 'callBack' object. I'll need to make a distinction if the user handler passed in another handler - say Handler2

The fact that I need to use enums to implement, what is effectively my own type-system (in the line of a discrimatory union - aka, a variant), is also a sure sign that the design needs a little re-thinking so in that case I'm open for a redesign. Having to have N-1 dummy handlers (ie, at any one time only one handler is being used and the others are just there doing nothing) defined in the class screams confused and low cohesive object model but who knows.

Ephemera
  • 8,672
  • 8
  • 44
  • 84
ma740988
  • 11
  • 3

1 Answers1

0

You could implement this using a functor, derived from a virtual base class:

struct CallbackBase
{
    // Dummy virtual functions that does nothing
    virtual operator()(DataLink const &, Metadata const &, Image const &) {}
    virtual operator()(Metadata const &, Image const &) {}
    virtual operator()(Image const &) {}
};

class Worker
{
    CallbackBase &callback_;

public:
    Worker(const CallbackBase &callback)
        : callback_(callback)
        { }

    void Image()
        {
            // Do something...

            callback_(img);
        }

    void Metadata()
        {
            // Do something...

            callback_(meta, img);
        }

    void Dlink()
        {
            // Do something...

            callback_(dlink, meta, img);
        }
};

struct MyCallback : public CallbackBase
{
    virtual operator()(Image const &)
        {
            // Do something useful here
        }
};

MyCallback my_callback;
Worker my_worker(my_callback);

Because of the overloads in the base callback class, the Worker class can call any of the of them in the correct place, while you only implement the callback you actually need in the derived callback class.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621