我正在尝试实现可以绑定范围的我自己的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++ 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 :(得分:3)
据我所知,这在Boost中不存在,因为它可以使用for_each
和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;
};
答案 1 :(得分:0)
我看不出问题所在。你说这可以通过调用代码中的for_each构造来实现。是的,没错。那么为什么不把for_each构造INTO到bind_range函子本身呢?我的意思是,bind_range将是一个带有operator()的结构模板。在此运算符中,您必须执行for_each。我错过了什么吗?
答案 2 :(得分: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 ⦥
};
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,
}