C++中for_each的应用
C++中for_each的应用
for each语法是方便的,也是很自然的,这也是为什么很多语言都有这样的语法,就我所知,包括java(jdk5.0以上),python,php,asp.net等语言都有类似的语法,甚至微软为C++/CLI中也添加了这样的语法。但是很遗憾的是,C++98标准中没有,于是,我们只能通过可悲的for_each算法去模拟。。。。。。。。。。先看看原生的语法是多么方便和自然的吧,虽然有人将其视为语法糖,但是,就算是糖,这也是很甜的那种。
先看看Python中的循环,虽然不是for each,但是类似于。
l = [1,2,3,4,5]
for i in l:
print i
简洁,干净,
假如你有幸使用微软的托管C++,你可以使用类似的语法:
using namespace System;
#include <list>
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for each ( int i in l)
Console::Write(i);
system("PAUSE");
}
虽然作为强类型语言,在声明方面稍微复杂点,循环的处理还是那么简洁,干净。
再来看看现有的C++中的:
#include <list>
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 同样是需要输出
for(list<int>::const_iterator lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit <<endl;
}
system("PAUSE");
}
繁复到我都不想说了,list<int>::const_iterator似的迭代器声明语法不符合一处定义的原则,冗余信息太多。(C++09添加的auto用法就是解决此问题的),即便是解决了此问题,还是会发现,在C++中写个循环比在python(仅仅是一个例子,其他有类似for each特性的语言都比C++简单)中复杂太多了。而循环实在是太过于常见的语法了,所以一次又一次使用这种本可以简单,但是受限于语法而搞得这么复杂的C++可怜语法的时候,我总是忍不住想要吐血。对于这么简单的例子,我们是可以找到一些方法来稍微简化一点的。没有for each语法,我们起码还有for_each算法-_-!
于是可以这样:
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 同样是需要输出
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
在加大了理解难度后(本来for each语法多简单啊,现在还要理解ptr_fun这样的函数对象生成的辅助函数),我们的循环是稍微简单一点了,虽然在这个例子中我们甚至要额外写函数-_-!虽然说函数可以只写一次,循环可是常常用的啊。
对于这样简单的例子,已经可以看出没有for_each语法的痛苦了,再复杂一点的例子
对于类成员函数的调用,看看有for_each的情况
python中:
class Add():
def __init__(self, i):
self._i = i
def add(self):
self._i += 1
def __str__(self):
return str(self._i)
s = [Add(1), Add(2), Add(3)]
for a in s:
a.add()
for a in s:
print a
这里拆分成两个函数,可以看出我的无奈,想要在一个for_each语法中连续调用两个函数的方法。。。。目前只有再写一个函数,而这个函数的作用就是仅仅调用这两个函数提供给for_each使用。不说这些丧气+无奈的话了,光是调用一个类的成员函数的可能还是有的。
C++中:
#include <list>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
class CAdd
{
public:
CAdd(int ai):mi(ai) { }
void add() { ++mi; }
operator int() { return mi;}
int mi;
};
int main()
{
CAdd a[3] = { CAdd(1), CAdd(2), CAdd(3)};
list<CAdd> l(a, a+3);
// 同样是需要输出
for_each(l.begin(), l.end(), mem_fun_ref(&CAdd::add));
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
为了实现循环的简洁,重新引入了新的复杂度,mem_fun_ref,希望一般的C++程序员见过这样的函数对象辅助函数。。。。还多了类似&CAdd::add这样的成员函数指针的语法,希望一般的程序员也能理解。。。。(不提有for each语法的语言中除了for each这样自然的语法外,做多复杂的运算都没有引入任何新的复杂度),最主要的是,你想要在一条for_each中实现两个函数的调用,你除了老老实实的实现一个新的函数外,就是像我这样了,调用for_each两次,两种方法都是不那么容易让人接受。。。。。。。。但是,在现有的C++中,我们也就只能做到这样了。既然用C++,就接受现实吧。其实,显示远比一般人想象的要复杂。
以上情况还是函数没有参数的时候,当函数有参数的时候,新的问题又来了。
看看python中这样一个简单的功能:
def add(a,b):
return a + b
l = [1,2,3,4,5]
for i in l:
print add(i,1)
无非就是在每个输出的函数中调用一个函数,没有任何值的一提的地方,是个人就能看懂。
在C++需要实现成下面这个样子:
#include <list>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
template <typename T>
class Add : public binary_function<T, T, void>
{
public:
void operator()(const T& ai, const T& aj) const
{
cout <<(ai + aj) <<endl;
}
};
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for_each(l.begin(), l.end(), bind2nd(Add<int>(), 1));
system("PAUSE");
}
到这一步,我希望大部分的C++程序员还能看懂什么意思及其实现的机制。。。。但是仅仅是我的希望吧,甚至我怀疑,这样的实现放在工作中,总监和老总是不是会将我批的体无完肤,的确,为了省略一个循环值得这样做吗?实在不值得,但是C++提供给你的机制就是这样。Add这样的函数对象构造复杂,还得利用trail机制(从binary_function类继承过来),然后再利用函数适配器bind2nd/bind1st,这样的东西似乎需要语言专家来解释,我是解释不清楚了,再加上更加复杂的函数连标准库中的bind都肯定不够用,还只能用boost::bind库,去试试吧,然后会发现一般的函数指来指去(特别是类成员)用的太复杂了,还是用boost::funciton吧。。。。。似乎永无止境。但是有了for each语法,那么什么复杂度都没有。。。。。还想自虐吗?算了吧,我基本上已经放弃了。不给糖吃,也放不着自己开工厂制作。。。。
另外,对于能够用boost的兄弟们,糖是有的吃的。boost:: foreach库即是如此。
下面是boost:: foreach的例子
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
BOOST_FOREACH( int i, l)
{
cout <<i <<endl;
}
BOOST_FOREACH( int i, l)
{
cout <<i+1 <<endl;
}
system("PAUSE");
}
就算仅仅这一个例子。。。。永远不要怪库开发者(比如boost,ace,loki)将C++语言弄得多么扭曲,他们也是出于无奈。。。。别去看实现,先只管用吧。
对于不能用boost的我。。。。只能看有没有办法偷偷的将/cli编译选项打开了。。。^^
C++中for_each的应用的更多相关文章
- Java中for_each循环的使用
最近在看一些和安卓相关的书籍,看到了for_each这种循环结构,这是为了简化java的for循环而改造的一种方便使用的格式. 格式如下: for(数据类型 变量:集合) 语句块 接下来看一个例程: ...
- C++11 中值得关注的几大变化(网摘)
C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...
- C++11 中值得关注的几大变化(详解)
源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里. ...
- STL中mem_fun, mem_fun_ref用法
1.引言 先看一个STL中for_each的用法: #include <iostream> #include <vector> #include <algorithm&g ...
- C++ 11 之Lambda
1.Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包”,如果 lambda 函数没有传回值(例如 void ),其回返类型可被完全忽略. 定义在与 lambda ...
- 【现代程序设计】【homework-07】
C++11 中值得关注的几大变化 1.Lambda 表达式 Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包”,如果 lambda 函数没有传回值(例如 void ...
- Python开源框架
info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...
- 记录 C++ STL 中 一些好用的函数--持续更新 (for_each,transform,count_if,find_if)
在日常的编程中,有这么几种操作还是比较常见的: 把一组数据都赋值成一个数,在一组数据中查找一个数,统计一组数据中符合条件的数等等. 一般的写法可以用循环,没有什么是循环不能搞定的.假如在这里怎么用介绍 ...
- 45 孩子们的游戏(圆圈中最后剩下的数) + list操作总结+ for_each多记忆容易忘记
题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机指 ...
随机推荐
- java bio总结
.同步异步.阻塞非阻塞(目前不是很清楚,这篇博客写完后,后续进行处理) 1.同步和异步:关注的是消息的通讯机制, 同步:发起调用后,如果没有得到结果,该调用是不会返回的:该调用者会主动等待调用返回. ...
- windows下安装nginx,并添加至系统服务
安装:解压修改配置文件运行即可 添加服务 需要借助"Windows Service Wrapper"小工具下载地址:winsw GitHub 下载后放在nginx目录下,并修改名字 ...
- 039、Data Volume 之 bind mount (2019-02-28 周四)
参考https://www.cnblogs.com/CloudMan6/p/7142150.html Date Volume 本质上是Dokcer host文件系统中的目录或者文件,能够直接被 ...
- SQL Server进阶(七)集合运算
概述 为什么使用集合运算: 在集合运算中比联接查询和EXISTS/NOT EXISTS更方便. 并集运算(UNION) 并集:两个集合的并集是一个包含集合A和B中所有元素的集合. 在T-SQL中.UN ...
- linux上安装mysql,tomcat,jdk
Linux 上安装 1 安装jdk 检测是否安装了jdk 运行 java –version 若有 需要将其卸载 a) 查看安装哪些jdk rmp –qa |grep java b) ...
- tensorflow---alexnet training (tflearn)
# 输入数据 import input_data mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) imp ...
- struct详解
正常定义一个数据结构都是这样用 typedef struct{ int a; int b; }M; 在使用时 M a; 其实 struct是这样的 struct M{ int a; int b; }; ...
- Tomcat清理日志文件无法立即释放磁盘空间
1 自己删除了Tomcat的日志文件,但是依然显示磁盘百分百占用 进入Tomcat目录显示日志已经删除 查询磁盘空间依旧百分百占用 2 自己杀死Tomcat进程然后重启,成功释放空间 3 原因,通过网 ...
- MongoDB 学习手册 - CURD
mongoDB 增加数据 // mongoDB 增加数据: //新增数据insert( 字典 ) 表示插入一条数据,insert([字典]) 表示插入多条数据 // db.text01.insert( ...
- IMX6开发板学习烧写Linux-QT系统步骤做个笔记
平台:迅为-i.MX6开发板 烧写系统:Linux-QT <ignore_js_op> Qt系统的烧写,是使用 MfgTool2 工具,只需要简单的配置下. 打开 “Mfgt ...