从boost :: bind_t自动转换为boost :: function

时间:2015-08-31 09:52:56

标签: c++ implicit-conversion c++03 boost-bind boost-function

我有以下签名的方法:

template<typename T>
void
register_msg_action(const pmt::pmt_t& name,
      boost::function<T(pmt::pmt_t)> converter,
      boost::function<void(T)> action)

pmt_t是一个完整的类型,在你提出之前)

以及带有T converter(pmt::pmt_t)void converter(T)的重载(即原始C / C ++函数),以及上述boost::function<>和C样式函数参数的所有排列。这让我有4种不同的方法。

我想避免进一步增加方法的数量。但是,我最常见的事情就是调用

之类的东西
register_msg_action(pmt::mp("key"),
    pmt::to_long, /* "raw" function long(pmt_t) */
    boost::bind(&my_class::void_method_of_long, this, _1) /* CAVEAT */
);

我的方法是/* CAVEAT */参数可隐式转换为boost::function<void(T)>,但是,似乎并非如此(g ++ 5.1.1):

error: no matching function for call to ‘register_msg_action(pmt::pmt_t, boost::function<long int(boost::intrusive_ptr<pmt::pmt_base>)>&, boost::_bi::bind_t<void, void (*)(long int), boost::_bi::list1<boost::arg<1> > >)’
     register_msg_action(pmt::mp("hi"), long_function, boost::bind(&my_class::void_method_of_long, this ,_1));

......所有其他候选人(boost :: function,boost :: function); (T(pmt_t),升压::功能); (T(pmt_t),void(T))......

test.cc:56:1: note: candidate: template<class T> void register_msg_action(const pmt_t&, T (*)(pmt::pmt_t), boost::function<void(T)>)
 register_msg_action(const pmt::pmt_t& name,
 ^
test.cc:56:1: note:   template argument deduction/substitution failed:
test.cc:80:76: note:   ‘boost::_bi::bind_t<void, void (*)(long int), boost::_bi::list1<boost::arg<1> > >’ is not derived from ‘boost::function<void(T)>’
     register_msg_action(pmt::mp("key"), pmt::to_long, boost::bind(&my_class::void_method_of_long, this, _1));

现在,做

boost::function<void(long)> action (boost::bind(&my_class::void_method_of_long, this, _1));
register_msg_action(pmt::mp("key"), pmt::to_long, action);

工作得很漂亮。由于甚至有一个构造函数在boost::_bi::bind_t中使用boost::function,我想知道我必须做些什么才能使其工作,没有

  • 重新实现boost::function
  • 依赖于C ++ 11或更高版本(无法做到,遗留编译器支持)
  • 使用boost:phoenix进行函数式编程(本来会尝试这个,但我们必须支持的boost版本还没有phoenix

我害怕将第三个参数的类型添加为附加模板typename,因为这会破坏保证action(converter(pmt::pmt_t))工作所必需的参数列表类型安全性,老实说,我宁愿处理现在更多的代码比以后检查用户的模板化g ++错误。

1 个答案:

答案 0 :(得分:3)

问题是在T的模板参数中register_msg_action的签名中出现boost::function时。然后,如果您没有使用实际的boost::function对象调用它,则无法推断出它。如果您明确指定模板参数,它应该可以工作:

register_msg_action<long>(pmt::mp("key"),
    pmt::to_long, /* "raw" function long(pmt_t) */
    boost::bind(&my_class::void_method_of_long, this, _1)
);

如果您想在使用至少一个普通函数参数时保留推导T的选项,您可以选择在其T中明确地使boost::function不可推导使用方法:

template <class T>
struct NonDeduced
{
  typedef T type;
};

// T has to be specified explicitly at call site
template<typename T>
void
register_msg_action(const pmt::pmt_t& name,
      boost::function<typename NonDeduced<T>::type (pmt::pmt_t)> converter,
      boost::function<void(typename NonDeduced<T>::type)> action)

// T deducible from converter
template<typename T>
void
register_msg_action(const pmt::pmt_t& name,
      T converter(pmt::pmt_t),
      boost::function<void(typename NonDeduced<T>::type)> action)

// T deducible from action
template<typename T>
void
register_msg_action(const pmt::pmt_t& name,
      boost::function<typename NonDeduced<T>::type (pmt::pmt_t)> converter,
      void action(T))

// T deducible from both, must match
template<typename T>
void
register_msg_action(const pmt::pmt_t& name,
      T converter(pmt::pmt_t),
      void action(T))

[Live example]