【问题标题】:Storing boost function存储升压功能
【发布时间】:2010-08-31 06:57:06
【问题描述】:

我必须存储不同 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 */ }

现在我有地图增强功能,用枚举中的给定类型打包到 any 中,以便将来识别它。现在我必须调用给定的函数。来自 any 的铸造不起作用:

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 对象?

【问题讨论】:

  • 您是否在case 1 中忘记了break
  • @KennyTM 是的,但它仍然失败。

标签: c++ casting boost-function any


【解决方案1】:

@TC 提供了运行时错误的解决方案。但我相信你应该使用Boost.Variant 而不是Boost.Any,因为它只能存储固定的类型选择。使用 Boost.Variant,您也可以消除该枚举,因为它已经提供了标准的访问者模式接口。 (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;
}

【讨论】:

  • @KennyTM hm,如何获取返回值? boost::apply_visitor(call_visitor(), row.second)
  • @Ockonal:循环体应该在call_visitor中完成。所以,例如void operator() (const T&amp; operand) const { std::cout &lt;&lt; operand() &lt;&lt; std::endl; }
  • @KennyTM,嗯,我明白这一点。但是如何将它存储到需要的变量中,例如 int、float、double?可能吗?也许有什么方法可以获取 boost 函数的返回类型并使用它进行变量?
  • @Ock: ... typename T::result_type result = operand(); ...
【解决方案2】:

从外观上看,row.first 是回调的名称,string。你应该使用row.second.first:

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

此外,您应该在开关中使用枚举常量 (case CLASS::e_int:),而不是幻数。

【讨论】:

  • >你应该使用你的枚举常量;为什么?
  • @Ockonal:因为它更安全。考虑一下如果您后来决定也想要一个 e_char 常量并且不小心将它添加为枚举中的第一个常量会发生什么。现在所有其他枚举值都发生了变化,您也必须修复开关中的幻数,否则会有一个讨厌的错误。
猜你喜欢
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-12
  • 2020-11-22
  • 1970-01-01
相关资源
最近更新 更多