3

我正在尝试实现自己的bind_range可以绑定范围的方法。它应该允许这样的客户端代码:

void f(int x, int y)
{
    std::cout << x + y << ',';
}

std::vector<int> v1; // contains 1,2,3

void go()
{
    boost::function<void(int y)> f_bound = bind_range(f, v1, _1);
    f_bound(10); // prints 11,12,13,
}

在上面的代码中,我的模板化bind_range检测到v1符合ForwardRangeConcept<>并且其值类型与f()的第一个参数兼容。然后它生成一个函数对象,该函数对象将遍历v1,调用f()每个值。

我知道上述可以通过调用代码中的某种形式的 for-each 构造来实现,但我想采用绑定函数并在以后使用它。

以上是我想要实现的本质。我已经阅读了我的C++ 模板元编程副本并查看了boost::bind实现,但我无法开始使用解决方案。我也有一种挥之不去的感觉,像这样的东西已经存在于 Boost 库的某个地方。

扩展:

绑定多个范围。 例如:

std::vector<int> v10; // contains 10,20,30

void go_multiple()
{
    boost::function<void()> f_bound = bind_range(f, v10, v1);
    f_bound(); // prints 11,12,13,21,22,23,31,32,33,
}

处理返回类型。 我不需要迭代调用的返回类型,但可以想象有人可能想要存储或处理每个返回值。我确信这可以通过某种 Lamda 类型的构造巧妙地完成。

4

3 回答 3

3

据我所知,这在 Boost 中不存在,因为它很容易用for_eachand复制bind,例如:

function<void()> bound = bind(
    for_each<vector<int>::iterator, function<void(int)> >, 
    v1.begin(), v1.end(), func
);`

这很简单。您只需要创建一个模板化仿函数bind_range,其构造函数采用绑定信息(即容器和仿函数)以及operator()将函数应用于容器的构造函数。

但是请注意,保存这样的函子以供以后使用通常是危险的,因为该bind_range对象最终可能会引用不再存在的容器。

一个简单的例子:

template<typename Container, typename Function>
struct bind_range {
    bind_range(Container& target, Function func) 
        : container(target), function(func) { }

    void operator()() {
        std::for_each(container.begin(), container.end(), function);
    }

    Function function;
    Container& container;
};
于 2011-03-31T12:20:12.070 回答
0

我不明白问题是什么。您说这可以通过调用代码中的 for_each 构造来实现。是的。那么为什么不将 for_each 构造放入 bind_range 函子本身呢?我的意思是,bind_range 将成为一个带有 operator() 的结构模板。在此运算符中,您必须执行 for_each。我错过了什么吗?

于 2011-03-31T09:25:08.357 回答
0

我在这方面做了一些工作,这就是我想出的。它有效,但不完整,因为只有范围绑定到第一个参数的一元函数和二元函数的模板。如果有人更进一步并使其更通用,请在此处发回。

#include <boost/bind.hpp>
#include <boost/range.hpp>
#include <boost/range/value_type.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/foreach.hpp>

template <class Range>
struct GetRangeValue
{
    typedef typename boost::range_value<Range>::type Value;
};

template <class Function, class Range>
struct BindForEachBase
{
    BindForEachBase(Function *f, Range &r) : function(f), range(r) { }
    Function *const function;
    Range &range;
};

template <class Function, class Range>
struct BindForEach1
    : BindForEachBase<Function, Range>
{
    BindForEach1(Function *f, Range &r) 
        : BindForEachBase(f, r) 
    { }
    void operator()() 
    { 
        BOOST_FOREACH(GetRangeValue<Range>::Value v, range) (*function)(v); 
    }
};

template <class Function, class Range>
BindForEach1<Function, Range> 
bindForEach(Function *f, Range &r)
{
    return BindForEach1<Function, Range>(f, r);
}

template <class Function, class Range, class A1>
struct BindForEach2
    : BindForEachBase<Function, Range>
{
    BindForEach2(Function *f, Range &r) 
        : BindForEachBase(f, r) 
    { }
    void operator()(A1 a1)
    {
        boost::function1<void, GetRangeValue<Range>::Value> f(boost::bind(*this->function, _1, a1));
        bindForEach(&f, range)();
    }
};

template <class Function, class Range, class Placeholder1>
typename boost::enable_if
<
    boost::is_placeholder<Placeholder1>, 
    BindForEach2<Function, Range, typename boost::function_traits<Function>::arg2_type> 
>::type 
bindForEach(Function *f, Range &r, Placeholder1 p1)
{
    return BindForEach2<Function, Range, boost::function_traits<Function>::arg2_type >(f, r);
}

void f(int x, int y)
{
    std::cout << x + y << ',';
}

#include <boost/assign/std/vector.hpp>
#include <vector>
using namespace boost::assign;

void go()
{
    std::vector<int> v1; 
    v1 += 1,2,3;
    boost::function<void(int y)> f_bound = bindForEach(f, v1, _1);
    f_bound(10); // prints 11,12,13,
}
于 2011-04-01T13:11:04.937 回答