Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass "Any kind of data" to a function in C++

Lets say I have a class Handler with some subclasses like stringhandler, SomeTypeHandler, AnotherTypeHandler. The class Handler defines a method "handle" as a common interface for all the subclasses. The logic to "handle" is ofcourse completely different for the different handlers.

So what I need to do is pass a value of anything to the handle method. The specific classes can then cast the "anything" to the type they expect.

Basically what I need is something like the java class Object :D

The first thing I tried was a void*, but apparently you can not do B* someB = dynamic_cast<B*>(theVoidPointer), so no luck there.

My second idea was to use boost::any. however, the requirement to use boost::any is that the value must be copy cunstructable, which is not the case for my data.

Any ideas to get this to work?

Thanks

EDIT: Note that I know I could use a SomeData class with no members at all, and let my data be subclasses of that, but I am looking for a more generic approach which does not require me to make my own wrapper class.

like image 817
W. Goeman Avatar asked Apr 10 '12 14:04

W. Goeman


2 Answers

You can for example define a base class:

class BaseHandlerData {
   ...
};

Then derive your specific data classes, which are expected by your handlers:

class StringData: public BaseHandlerData {
   ...
};

class SomeData: public BaseHandlerData {
   ...
};

Then you should be able to pass a BaseHandlerData* argument to the handle method, and use something like:

void handle(BaseHandlerData *data) {
    StringData* stringData = dynamic_cast<StringData*>(...);
    // handle your string data here ...
}

to safely cast to your expected data type.

Gerald

like image 29
nutrina Avatar answered Oct 03 '22 04:10

nutrina


Okay, here is a simple approach using boost::any to hold pointers to your datatypes. However, beware that boost::any adds some overhead code decreasing performance slightly (in most cases neglectible).. consider using boost::spirit::hold_any instead, or void* if you don't need type safety.

class Handler {
public:
    void handle( boost::any value ) { 
        do_handle( value );
    }
private:
    virtual void do_handle( boost::any& value ) = 0;
};

template<class T>
class HandlerBase : public Handler {
private:
    void do_handle( boost::any& value ) {
        // here you should check if value holds type T*...
        handle_type( *(boost::any_cast<T*>( value )) );
    }

    void handle_type( const T& value ) = 0;
};

class StringHandler : HandlerBase<std::string> {
private:
    void handle_type( const std::string& value ) {
        // do stuff
    }
};

Now you can write lots of handler classes, deriving from HandlerBase, without assuming that the handled types have a common base class.

like image 196
fdlm Avatar answered Oct 03 '22 03:10

fdlm