【问题标题】:Using boost::bind but allowing any additional parameters to be passed through使用 boost::bind 但允许传递任何其他参数
【发布时间】:2014-12-20 19:18:22
【问题描述】:

我正在组合一个“简单”的模板类。它提供了对数据库执行某些操作的接口,因此还有其他成员(主要用于对容器成员进行操作)。然而,就我们的目的而言,模板类看起来像这样:

template<typename T, //the type of objects the class will be manipulating
         typename S> //the signature of the function the class will be using
FunctionHandler
{
private:
    std::vector<T> container;
    boost::function<S> the_operation;
    SomeClass* pSC; //a database connection; implementation unimportant

    //some other members--not relevant here
public:
    boost::function<???> Operate;
    FunctionHandler(boost::function<S> the_operation_)
        : the_operation(the_operation_)
    {
        Operate = boost::bind(the_operation, pSC, std::back_inserter<std::vector<T> >,
                              /*infer that all other parameters passed to Operate
                                should be passed through to the_operation*/);
    }

    //other peripheral functions
}

我的问题有两个。

  1. 我将什么作为Operate 的模板参数。即替换???
  2. 我如何告诉boost::bind 它应该将给Operate 的任何其他参数传递给the_operation?换句话说,对于一些看起来像void (SomeClass*, std::back_insert_iterator&lt;std::vector&lt;T&gt; &gt;, int, bool) 的任意函数签名S 和看起来像void (SomeClass*, std::back_insert_iterator&lt;std::vector&lt;T&gt; &gt;, double, double, bool) 的一些其他任意函数签名O 我如何编写这个模板类,使得Operate 的签名为@第一个为 987654332@,第二个为 void (double, double, bool),并将其值传递给 the_operation 的第 3-N 个参数?

在我的搜索中,我找不到任何与此类似的问题。

【问题讨论】:

  • 编译器应该如何检查参数类型是否与函数参数类型兼容?它应该如何插入从参数类型到函数参数类型的转换?
  • 我不知道。回答这是回答问题的一部分,不是吗?预期用途是在编译时和运行时参数类型与参数类型匹配。
  • 据我所知,任意类型的集合是不可能的。当您将某些内容存储在boost::function 中时,您会删除有关它的所有信息(对于外部)并用单个接口(返回值+参数类型)替换它。 boost::function 似乎也不支持省略号。您可以通过在boost::function 的函数签名中添加类似void* 的内容,然后通过此指针传递其他参数来解决该问题。但是,这既不包括类型检查也不包括转换。
  • 在这种情况下,我想要的东西不能直接通过boost::function 获得。我可以尝试其他可能的实现吗?
  • @caps Lemme 确保我理解正确。你有S 是一些函数,比如说,4 个参数......并且你想绑定前两个参数,并让结果是一个函数,它接受 2 个参数并调用 the_operation 与 2 个绑定的参数和两个通过了?

标签: c++ templates boost c++03 boost-bind


【解决方案1】:

为什么还要使用绑定?没有它我们也能得到同样的效果。我使用Iter 作为模板,但您可以使用正确的类型填写:

template <typename S, typename Iter>
class Operator
{
    boost::function<S> func_;
    SomeClass* cls_;
    Iter iter_;

public:
    Operator(function<S> func, SomeClass* cls, Iter iter)
    : func_(func), cls_(cls), iter_(iter)
    { }

    // one for each # of args
    typename boost::result_of<
        boost::function<S>(SomeClass*, Iter)
    >::type operator()() const {
        return func_(cls_, iter_);
    }

    template <typename A>
    typename boost::result_of<
        boost::function<S>(SomeClass*, Iter, A)
    >::type operator()(A a) const {
        return func_(cls_, iter_, a);
    }

    template <typename A, typename B>
    typename boost::result_of<
        boost::function<S>(SomeClass*, Iter, A, B)
    >::type operator()(A a, B b) const {
        return func_(cls_, iter_, a, b);
    }

    // etc.
};

我们正在制作所有的operator()s,但它们只有在被调用时才会被实例化——所以只要你调用了正确的(对于任何解决方案,你都必须这样做),这行得通。

【讨论】:

  • 这里需要使用boost::result_of吗?我不能将返回类型作为模板的另一个参数吗?
  • @caps 这将是多余的。返回类型是S 的一部分。
  • 是的,但是如果我自己传递返回类型,我就不需要使用boost::result_of。 “使用 boost”是我的同事喜欢尽可能少做的事情,出于各种好的和坏的原因。我可能会先浮动result_of 解决方案,我只需要知道没有它是否可以通过。
  • @caps 你已经在使用 boost。你可以使用 C++11 吗?我可以给你一个非升压 C++11 解决方案:)
  • 不,就我们的目的而言,C++11 在我们的 IDE 中并不真正可用。我们确实使用boost,但我们的方法是“在您需要时使用boost。”
【解决方案2】:

不幸的是,没有办法“推断”所有其余的论点。您必须指定所有正确的占位符。从 C++03 开始​​,我们可以使用很多模板特化。

template <typename S> struct Operate;

template <typename R, typename Iter>
struct Operate<R(SomeClass*, Iter)>
{
    using namespace boost;

    function<R()> op_;

    Operator(function<R(SomeClass*, Iter)> op, SomeClass* cls, Iter iter)
    : op_(bind(op, cls, iter))
    { }
};

template <typename R, typename Iter, typename A>
struct Operate<R(SomeClass*, Iter, A)>
{
    using namespace boost;

    function<R(A)> op_;

    Operator(function<R(SomeClass*, Iter, A)> op, SomeClass* cls, Iter iter)
    : op_(bind(op, cls, iter, _1))
    { }
};

template <typename R, typename Iter, typename A, typename B>
struct Operate<R(SomeClass*, Iter, A, B)>
{
    using namespace boost;

    function<R(A, B)> op_;

    Operator(function<R(SomeClass*, Iter, A, B)> op, SomeClass* cls, Iter iter)
    : op_(bind(op, cls, iter, _1, _2))
    { }
};

// etc.

它很冗长,但如果你不能使用 C++11,我不知道你还能做什么。其中,为了完整起见:

template <typename R, typename Iter, typename... Extra>
struct Operator<R(SomeClass*, Iter, Extra...)>
{
    std::function<R(SomeClass*, Iter, Extra...)> op_;
    SomeClass* cls_;
    Iter iter_;

    Operator(function<R(SomeClass*, Iter, Extra...)> op, SomeClass* cls, Iter iter)
    : op_(op), cls_(cls), iter_(iter)
    { }

    R operator()(Extra... args) const {
        return op_(cls_, iter_, args...);
    }
};

【讨论】:

    【解决方案3】:

    不幸的是,我对 boost.MPL 的了解非常有限,所以我认为这不是解决从函数类型中删除前两个参数类型问题的最佳方法。 p>

    #include <boost/function_types/components.hpp>
    #include <boost/function_types/function_type.hpp>
    #include <boost/mpl/erase.hpp>
    #include <boost/mpl/begin_end.hpp>
    #include <boost/mpl/advance.hpp>
    #include <boost/mpl/int.hpp>
    
    template<typename F, int N>
    class remove_first_N_param_types
    {
            typedef typename boost::function_types::components<F>::type
        components;
            typedef typename boost::mpl::begin<components>::type
        beg;
            typedef typename boost::mpl::advance<beg, boost::mpl::int_<1  >>::type
        beg_param;
            typedef typename boost::mpl::advance<beg, boost::mpl::int_<1+N>>::type
        beg_param_plus_N;
            typedef typename boost::mpl::erase<components,
                                               beg_param, beg_param_plus_N>::type
        erased_first_N_params;
    
    public:
            typedef typename boost::function_types::
            function_type<erased_first_N_params>::type
        type;
    };
    

    Live example

    【讨论】:

    • 这给了你类型,但你将如何构造它?
    • 是的,这可以让您将Operate 定义为boost::function&lt;remove_first_N_param_types&lt;F, 2&gt; &gt; Operate,虽然很酷,但它并没有展示如何从member_function 构造Operate。不过,我会对此投赞成票,因为我怀疑它将来可能对读者有用。
    • @caps d'oh,我已经为 C++11 做到了这一点,但我在 C++03 中找不到合适的方法来做到这一点——只能使用模仿可变参数模板的技术(类似于巴里的第一个答案)。可以通过使用boost::arg&lt;N&gt; 而不是命名占位符来简化它,但是手动重载或特化仍然存在,除非您使用宏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-11
    • 2013-11-12
    • 2020-04-11
    • 1970-01-01
    相关资源
    最近更新 更多