2011-03-31 36 views
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()

我知道上面的代码可以用调用代码中的每个构造的某种形式来实现,但我想要绑定函数并稍后使用它。

以上是我想达到的本质。我已阅读我的C++ Template Metaprogramming副本,并查看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型构造完成。

回答

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, 
} 
0

我没有看到问题所在。你说这可以通过调用代码中的for_each构造来实现。是的。那么为什么不把那个for_each构造放入bind_range函数本身呢?我的意思是,bind_range将会是一个带有operator()的结构模板。在这个操作符中,你必须做一个for_each。我错过了什么吗?

+0

也许这是一个简单的解决方案。我想我开始喜欢的东西'模板<....>结构bind_range:提高::绑定<....> {};'然后去上专门在那里一个参数是每种情况下??? – paperjam 2011-03-31 09:34:45

3

据我所知,这并不在升压存在的,因为它很容易与for_eachbind转载,例如:

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; 
}; 
+0

这工作,我认为其中'Function'是一元的最简单的情况。但我想用占位符,即'_1'等我建你的榜样,看看我现在只是一个小小的一步之遥绑定。 – paperjam 2011-03-31 13:36:41

+0

为了支持N进制的功能,你只需要创建模板'运营商()'重载取N个参数。另外请注意,您可以创建一个功能,如Boost.Bind做,而不需要用户明确说明模板参数返回一个'bind_range'对象。 – 2011-03-31 14:15:48