Хранение функции повышения - PullRequest
2 голосов
/ 31 августа 2010

Я должен хранить список различных boost :: function объектов.Чтобы обеспечить это, я использую boost :: any.У меня есть несколько функций, которые принимают сигнатуры различных функций, упаковывают их в any и затем вставляют в специальную карту с заданным типом.Вот код:

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 */ }

Теперь у меня есть функция повышения карты, упакованная в любой с заданным типом из enum, чтобы распознать его в будущем.Теперь я должен вызывать данные функции.Приведение из любого не будет работать:

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;
    }
}

Это не будет кастовать, и во время бега я получаю исключение:

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

Возможно ли преобразовать обратно boost :: function объект?

Ответы [ 2 ]

4 голосов
/ 31 августа 2010

@ TC предоставил решение для ошибки времени выполнения. Но я считаю, что вы должны использовать Boost.Variant вместо Boost.Any , поскольку существует только фиксированный выбор типов, которые он может хранить. С Boost.Variant вы также можете исключить это перечисление, поскольку оно уже обеспечивает стандартный интерфейс шаблонов посетителей. ( результат ):

#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;
}
3 голосов
/ 31 августа 2010

Судя по всему, row.first - это имя обратного вызова, a string.Возможно, вам следует использовать row.second.first:

case 0: // int
    any_cast< function<int ()> >(row.second.first)();
    break;

Более того, вы должны использовать свои константы перечисления в переключателе (case CLASS::e_int:) вместо магических чисел.

...