如何在 for_each 中组合函数和谓词?

发布于 2024-09-08 04:46:39 字数 873 浏览 1 评论 0原文

如何使用 for_each() 在容器的某些部分上调用函数

我创建了一个 for_each_if() 来执行 a

for( i in shapes )
    if( i.color == 1 )
        displayShape(i);

并且调用看起来像

for_each_if( shapes.begin(), shapes.end(),
                       bind2nd( ptr_fun(colorEquals), 0 ),
                       ptr_fun( displayShape ) );

bool colorEquals( Shape& s, int color ) {
    return s.color == color;
}

但是,我觉得模仿类似 STL 的算法不是我应该做的事情。

  1. 有没有办法仅使用现有的 STL 关键字来生成此内容?

    不想想做

     for_each(shapes.begin(),shapes.end(),
                       bind2nd( ptr_fun(display_shape_if_color_equals), 0 ) );
    

    因为,在更复杂的情况下,函子名称会误导函子的含义

  2. *有没有办法访问结构体的成员(例如colorEquals) 对于像 for_each 这样的函数,无需创建函数? *

How can you call a Function over some part of a container, using for_each() ?

I have created a for_each_if() to do a

for( i in shapes )
    if( i.color == 1 )
        displayShape(i);

and the call looks like

for_each_if( shapes.begin(), shapes.end(),
                       bind2nd( ptr_fun(colorEquals), 0 ),
                       ptr_fun( displayShape ) );

bool colorEquals( Shape& s, int color ) {
    return s.color == color;
}

However, I feel immitating STL-like algorithms is not something that I should be doing.

  1. Is there a way to use only existing STL keywords to produce this ?

    I did not want to do a

     for_each( shapes.begin(), shapes.end(),
                       bind2nd( ptr_fun(display_shape_if_color_equals), 0 ) );
    

    because, in a more complicated case, the functor name would be misleading with respect to what the functor

  2. *Is there a way to access a struct's member (like colorEquals) for functions like for_each without having to create a function ? *

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

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

发布评论

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

评论(4

庆幸我还是我 2024-09-15 04:46:52

要将常规 for_each 与 if 一起使用,您需要一个模拟 if 条件的函子。

#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
#include <boost/bind.hpp>

using namespace std;

struct incr {
  typedef void result_type;
  void operator()(int& i) { ++i; }
};

struct is_odd {
  typedef bool return_type;
  bool operator() (const int& value) {return (value%2)==1; }
};


template<class Fun, class Cond>
struct if_fun {
  typedef void result_type;
  void operator()(Fun fun, Cond cond, int& i) {
    if(cond(i)) fun(i);
  }
};


int main() {
  vector<int> vec;
  for(int i = 0; i < 10; ++i) vec.push_back(i);

  for_each(vec.begin(), vec.end(), boost::bind(if_fun<incr, is_odd>(), incr(), is_odd(), _1));
  for(vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
    cout << *it << " ";
}

不幸的是,我的模板 hackery 还不够好,无法使用 bind1st 和 bind2nd 来管理它,因为它会以某种方式与作为 unary_function 返回的绑定器混淆,但使用 boost::bind< 看起来相当不错/代码> 无论如何。我的示例并不完美,因为它不允许传递给 if_fun 的 Func 返回,我想有人可以指出更多缺陷。欢迎提出建议。

To use a regular for_each with an if you would need a Functor that emulates an if condition.

#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
#include <boost/bind.hpp>

using namespace std;

struct incr {
  typedef void result_type;
  void operator()(int& i) { ++i; }
};

struct is_odd {
  typedef bool return_type;
  bool operator() (const int& value) {return (value%2)==1; }
};


template<class Fun, class Cond>
struct if_fun {
  typedef void result_type;
  void operator()(Fun fun, Cond cond, int& i) {
    if(cond(i)) fun(i);
  }
};


int main() {
  vector<int> vec;
  for(int i = 0; i < 10; ++i) vec.push_back(i);

  for_each(vec.begin(), vec.end(), boost::bind(if_fun<incr, is_odd>(), incr(), is_odd(), _1));
  for(vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
    cout << *it << " ";
}

Unfortunately my template hackery isn't good enough to manage this with bind1st and bind2nd as it somehow gets confusing with the binder being returned being a unary_function but it looks pretty good with boost::bind anyhow. My example is no means perfect as it doesn't allow the Func passed into if_fun to return and I guess somebody could point out more flaws. Suggestions are welcome.

旧人 2024-09-15 04:46:49

您可以使用 C++20 范围。这是一个我们将 std::vector 的所有偶数加一的示例。

#include <ranges>
#include <algorithm>
#include <vector> 

namespace ranges = std::ranges;

std::vector<int> vec = {1, 2, 3, 4, 5};
const auto even = [](int i) { return 0 == i % 2; };
ranges::for_each(vec | std::views::filter(even), [](int& i){ i+=1;});

您可以在编译器资源管理器上找到一个活生生的示例此处

You can use the C++20 ranges. Here an example where we add one to all even numbers of a std::vector

#include <ranges>
#include <algorithm>
#include <vector> 

namespace ranges = std::ranges;

std::vector<int> vec = {1, 2, 3, 4, 5};
const auto even = [](int i) { return 0 == i % 2; };
ranges::for_each(vec | std::views::filter(even), [](int& i){ i+=1;});

You can find a living example on compiler explorer here

城歌 2024-09-15 04:46:46

使用升压范围适配器要简洁得多。

using boost::adaptor::filtered;
using boost::bind;

class Shape {
  int color() const;
};

void displayShape(const Shape & c);

bool test_color(const Shape & s, int color ){
    return s.color() == color;
}

boost::for_each
    ( vec | filtered(bind(&test_color, _1, 1)
    , bind(&displayShape, _1)
    )

请注意使用新的范围库来抽象
支持范围和范围适配器的迭代器
库来组成操作管道。

所有基于标准 stl 迭代器的算法都具有
已移植到基于范围的算法。

想象一下

typedef boost::unordered_map<int, std::string> Map;
Map map;
...
using boost::adaptor::map_keys;
using boost::bind
using boost::ref
using boost::adaptor::filtered; 

bool gt(int a, int b)
{ return a > b };

std::string const & get(const Map & map, int const & a)
{ return map[a] }

// print all items from map whose key > 5
BOOST_FOREACH
    ( std::string const & s
    , map 
        | map_keys 
        | filtered(bind(>, _1, 5)) 
        | transformed(bind(&get, ref(map), _1))
    )
    {
        cout << s;
    }

阅读范围适配器< /a> 和 范围算法

Using boost range adaptors is much neater.

using boost::adaptor::filtered;
using boost::bind;

class Shape {
  int color() const;
};

void displayShape(const Shape & c);

bool test_color(const Shape & s, int color ){
    return s.color() == color;
}

boost::for_each
    ( vec | filtered(bind(&test_color, _1, 1)
    , bind(&displayShape, _1)
    )

Note the use of the new range library to abstract away
iterators in favor of ranges and the range adaptors
library to compose a pipeline of operations.

All the standard stl iterator based algorithms have
been ported to range based algorithms.

Imagine this

typedef boost::unordered_map<int, std::string> Map;
Map map;
...
using boost::adaptor::map_keys;
using boost::bind
using boost::ref
using boost::adaptor::filtered; 

bool gt(int a, int b)
{ return a > b };

std::string const & get(const Map & map, int const & a)
{ return map[a] }

// print all items from map whose key > 5
BOOST_FOREACH
    ( std::string const & s
    , map 
        | map_keys 
        | filtered(bind(>, _1, 5)) 
        | transformed(bind(&get, ref(map), _1))
    )
    {
        cout << s;
    }

Read Range Adaptors and Range Algorithm.

小猫一只 2024-09-15 04:46:44

模仿类似 STL 的算法正是您应该做的。这就是它们出现在 STL 中的原因。

具体来说,您可以使用仿函数而不是创建实际的函数并绑定它。这确实整洁多了。

template<typename Iterator, typename Pred, typename Operation> void 
for_each_if(Iterator begin, Iterator end, Pred p, Operation op) {
    for(; begin != end; begin++) {
        if (p(*begin)) {
            op(*begin);
        }
    }
}
struct colorequals {
    colorequals(int newcol) : color(newcol) {}
    int color;
    bool operator()(Shape& s) { return s.color == color; }
};
struct displayshape {
    void operator()(Shape& s) { // display the shape }
};
for_each_if(shapes.begin(), shapes.end(), colorequals(0), displayshape());

这通常被认为是惯用的方法。

Imitating STL-like algorithms is exactly what you should be doing. That's why they're in the STL.

Specifically, you can use a functor instead of creating an actual function and binding it. This is much neater, really.

template<typename Iterator, typename Pred, typename Operation> void 
for_each_if(Iterator begin, Iterator end, Pred p, Operation op) {
    for(; begin != end; begin++) {
        if (p(*begin)) {
            op(*begin);
        }
    }
}
struct colorequals {
    colorequals(int newcol) : color(newcol) {}
    int color;
    bool operator()(Shape& s) { return s.color == color; }
};
struct displayshape {
    void operator()(Shape& s) { // display the shape }
};
for_each_if(shapes.begin(), shapes.end(), colorequals(0), displayshape());

This is usually considered the idiomatic way to go.

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