将函数绑定到范围以创建迭代函数

发布于 2024-10-28 16:31:47 字数 1182 浏览 1 评论 0原文

我正在尝试实现我自己的可以绑定范围的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<> 及其值type 与 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 类型的构造来巧妙地完成。

I am trying to implement my own bind_range that can bind against a range. It should allow client code like this:

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

In the above code, my templated bind_range detects that v1 conforms to ForwardRangeConcept<> and that its value type is compatible with f()'s first parameter. It then generates a function object that will iterate over v1, calling f() for each value.

I know that the above could be achieved with some form of for-each construct in the calling code but I want to take the bound function and use it later.

The above is the essence of what I want to achieve. I have read my copy of C++ Template Metaprogramming and looked at the boost::bind implementation but I can't get started with a solution. I also have the nagging feeling that something like this already exists already somewhere in the Boost libraries.

Extensions:

Binding multiple ranges. For example:

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

Dealing with return type. I don't need a return type from my iterated calls but it's conceivable that someone might want to store or process each return value. I'm sure this could be done neatly with some sort of Lamda-type construct.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

魄砕の薆 2024-11-04 16:31:47

据我所知,这在 Boost 中不存在,因为它很容易用 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;
};

As far as I'm aware, this doesn't exist in Boost, because it's easily reproduced with for_each and bind, for example:

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

It's fairly simple. You just need to create a templated functor bind_range with a constructor that takes the binding information (i.e. the container and functor) and an operator() that applies the function to the container.

Note, however, that saving a functor like this for later use is often dangerous, because the bind_range object could end up refering to a container that no longer exists.

A quick example:

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;
};
聚集的泪 2024-11-04 16:31:47

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

I don't see what the problem is. You said this could be achieved by a for_each construct in calling code. Yes, true. Then why not put that for_each construct INTO the bind_range functor itself? I mean, bind_range is going to be a struct template with operator(). In this operator you must do a for_each. Am I missing something?

吃→可爱长大的 2024-11-04 16:31:47

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

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

I worked on this a little and here is what I came up with. It works, but is incomplete as there are only templates for unary functions and binary functions where the range is bound to the first parameter. If anyone takes this further and makes it more generic, please do post back here.

#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,
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文