Search code examples
c++castingboost-functionany

Storing boost function


I have to store a list of different boost::function objects. To provide this I'm using boost::any. I have a few functions which takes different functions signatures, pack them into any and then insert into special map with given type. Here is the code:

enum TypeEnumerator
{
    e_int,
    e_float,
    e_double
};

typedef map< string, pair<any, TypeEnumerator> > CallbackType;
CallbackType mCallbacks;

void Foo(const string &name, function<float ()> f)
{
    mCallbacks[name] = make_pair(any(f), CLASS::e_float);
}
void Foo(const string &name, function<int ()> f) { /* the same, but with e_int */ }
void Foo(const string &name, function<double ()> f) { /* the same, but with e_double */ }

Now I have in map boost function, packed into any with given type from enum, to recognize it in future. Now I have to call given functions. The casting from any won't work:

BOOST_FOREACH(CallbackType::value_type &row, mCallbacks)
{
    // pair<any, TypeEnumerator>
    switch (row.second.second) // Swith the TypeEnumerator
    {
        case 0: // int
            any_cast< function<int ()> >(row.first)();
        break;
        case 1: // float
            any_cast< function<float ()> >(row.first)();
        break;
        case 2: // double
            any_cast< function<double ()> >(row.first)();
        break;
    }
}

This won't cast and during running I get the exception:

  what():  boost::bad_any_cast: failed conversion using boost::any_cast

Is it possible to convert back the boost::function object?


Solution

  • @TC provided the solution for the runtime error. But I believe you should use Boost.Variant instead of Boost.Any as there are only a fixed selection of types it can store. With Boost.Variant you could eliminate that enum too, as it already provided a standard visitor pattern interface. (result):

    #include <boost/variant.hpp>
    #include <boost/function.hpp>
    #include <boost/foreach.hpp>
    #include <map>
    #include <string>
    #include <iostream>
    
    typedef boost::variant<boost::function<int()>,
                           boost::function<float()>,
                           boost::function<double()> > Callback;
    typedef std::map<std::string, Callback> CallbackType;
    
    CallbackType mCallbacks;
    
    void Foo(const std::string& name, const Callback& f) {
        mCallbacks[name] = f;
    }
    
    //------------------------------------------------------------------------------
    
    float f() { 
        std::cout << "f called" << std::endl;
        return 4;
    }
    
    int g() {
        std::cout << "g called" << std::endl;
        return 5;
    }
    
    double h() {
        std::cout << "h called" << std::endl;
        return 4;
    }
    
    //------------------------------------------------------------------------------
    
    struct call_visitor : public boost::static_visitor<> {
        template <typename T>
        void operator() (const T& operand) const {
            operand();
        }
    };
    
    
    int main () {
        Foo("f", boost::function<float()>( f ));
        Foo("g", boost::function<int()>( g ));
        Foo("h", boost::function<double()>( h ));
    
        BOOST_FOREACH(CallbackType::value_type &row, mCallbacks) {
            boost::apply_visitor(call_visitor(), row.second);
        }
    
        return 0;
    }