简体   繁体   English

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

[英]automatic conversion from boost::bind_t to boost::function

I have a method of the following signature: 我有一个以下签名的方法:

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 is a complete type, before you ask) pmt_t是一个完整的类型,在你问之前)

as well as overloads that take T converter(pmt::pmt_t) and void converter(T) (ie raw C/C++ functions), as well as all permutations of the above boost::function<> and the C-style function arguments. 以及采用T converter(pmt::pmt_t)void converter(T) (即原始C / C ++函数)的重载,以及上述boost::function<>和C风格函数参数的所有排列。 That leaves me with 4 different methods already. 这让我有4种不同的方法。

I'd like to avoid increasing the number of methods further. 我想避免进一步增加方法的数量。 However, the most common thing I'll do is call something like 但是,我要做的最常见的事情就是打电话

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 */
);

My approach was that the /* CAVEAT */ argument is implicitly convertible to boost::function<void(T)> , but however, this doesn't seem to be the case (g++ 5.1.1): 我的方法是/* 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));

... all the other candidates (boost::function,boost::function); ...所有其他候选人(boost :: function,boost :: function); (T(pmt_t),boost::function); (T(pmt_t),升压::功能); (T(pmt_t), void(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));

Now, doing 现在,做

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

works beautifully. 工作得很漂亮。 Since there is even a constructor that takes boost::_bi::bind_t in boost::function , I wonder what I must do to make this work, without 因为甚至有一个构造boost::functionboost::function boost::_bi::bind_t ,我想知道我必须做些什么来使这个工作, 没有

  • reimplementing boost::function 重新实现boost::function
  • relying on C++11 or later (can't do, legacy compiler support) 依赖于C ++ 11或更高版本(无法做到,遗留编译器支持)
  • using boost:phoenix for functional programming (would have tried this, but the boost versions we must support don't all have phoenix yet. 使用boost:phoenix进行函数式编程(试过这个,但是我们必须支持的boost版本并不是所有的都有phoenix

I'm afraid of adding the type of the third argument as additional template typename, because that would break the parameter list type safety that is necessary to guarantee action(converter(pmt::pmt_t)) works, and honestly, I'd rather deal with more code now than examine user's templated g++ errors later on. 我害怕将第三个参数的类型添加为附加的模板类型名称,因为这会破坏保证action(converter(pmt::pmt_t))所必需的参数列表类型安全性action(converter(pmt::pmt_t)) ,并且老实说,我宁愿现在处理更多代码,而不是稍后检查用户的模板化g ++错误。

The problem is when T appears in the signature of register_msg_action within template arguments of boost::function . 问题是当T出现在boost::function模板参数中的register_msg_action的签名中时。 Then, if you're not calling it with an actual boost::function object, it cannot be deduced. 然后,如果你没有使用实际的boost::function对象调用它,则无法推断出它。 It should work if you specify the template argument explicitly: 如果您明确指定模板参数,它应该工作:

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

If you want to keep the option of deducing T when using at least one plain-function argument, you have the option to explicitly make the T non-deducible in its boost::function use: 如果你想在使用至少一个普通函数参数时保留推导T的选项,你可以选择在其boost::function使用中明确地使T不可导入:

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] [实例]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM