【问题标题】:automatic conversion from boost::bind_t to boost::function从 boost::bind_t 到 boost::function 的自动转换
【发布时间】:2015-08-31 09:52:56
【问题描述】:

我有以下签名的方法:

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&lt;&gt; 和 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&lt;void(T)&gt;,但是,情况似乎并非如此(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),boost::function); (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::function 中甚至有一个构造函数使用boost::_bi::bind_t,我想知道我必须做什么才能使这项工作,没有

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

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

【问题讨论】:

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


    【解决方案1】:

    问题是当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 的选项,您可以选择在其 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]

    【讨论】:

    • 确实如此!我将修改我的语法以使其成为一项功能,而不是给用户带来额外的负担。
    • 顺便说一句,强制我的用户指定模板参数会将我的方法编号减少到 1,我想这是一个改进。我认为强迫用户明确地做某事比让他有机会做一些会导致即使是具有提升经验的人也需要几分钟才能弄清楚编译器抱怨的事情要好。
    猜你喜欢
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 2011-09-01
    • 2011-09-13
    • 2016-03-16
    相关资源
    最近更新 更多