你怎么能叫Function上一些容器的一部分,使用for_each()?
我已经创建了for_each_if()一个
for( i in shapes )
if( i.color == 1 )
displayShape(i);
Run Code Online (Sandbox Code Playgroud)
电话看起来像
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;
}
Run Code Online (Sandbox Code Playgroud)
但是,我觉得模仿类似STL的算法并不是我应该做的事情.
有没有办法只使用现有的STL关键字来生成这个?
我不希望做一个
for_each( shapes.begin(), shapes.end(),
bind2nd( ptr_fun(display_shape_if_color_equals), 0 ) );
Run Code Online (Sandbox Code Playgroud)
因为,在一个更复杂的情况下,仿函数名称会对仿函数产生误导
*有没有办法访问结构的成员(如colorEquals),for_each无需创建函数等功能?*
模仿类似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());
Run Code Online (Sandbox Code Playgroud)
这通常被认为是惯用的方式.
使用升压范围适配器要简洁得多。
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)
)
Run Code Online (Sandbox Code Playgroud)
请注意使用新的范围库来抽象迭代器以支持范围,并使用范围适配器库来组成操作管道。
所有基于标准 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;
}
Run Code Online (Sandbox Code Playgroud)
您可以使用 C++20 范围。这是一个例子,我们将 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;});
Run Code Online (Sandbox Code Playgroud)
您可以在此处找到编译器资源管理器的实例
要将常规 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 << " ";
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我的模板 hackery 还不够好,无法使用 bind1st 和 bind2nd 来管理它,因为它以某种方式与返回的活页夹混淆,unary_function但无论如何它看起来都很好boost::bind。我的示例并不完美,因为它不允许传递给 if_fun 的 Func 返回,我想有人可以指出更多缺陷。欢迎提出建议。