2

さまざまなboost::functionオブジェクトのリストを保存する必要があります。これを提供するために、私はboost::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 */ }

今、私はマップブースト機能を持っており、将来それを認識するために、列挙型から与えられたタイプの任意のものにパックされています。次に、指定された関数を呼び出す必要があります。いずれからのキャストも機能しません:

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オブジェクトを元に戻すことは可能ですか?

4

2 に答える 2

4

@TCは、ランタイムエラーの解決策を提供しました。ただし、保存できるタイプの選択肢は固定されているため、 Boost.Anyの代わりにBoost.Variantを使用する必要があると思います。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;
}
于 2010-08-31T07:36:05.597 に答える
3

見た目からrow.first、コールバックの名前はstringです。おそらく使用する必要がありますrow.second.first

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

case CLASS::e_int:さらに、マジックナンバーの代わりに、スイッチ()で列挙型定数を使用する必要があります。

于 2010-08-31T07:13:48.287 に答える