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的应用的更多相关文章

  1. Java中for_each循环的使用

    最近在看一些和安卓相关的书籍,看到了for_each这种循环结构,这是为了简化java的for循环而改造的一种方便使用的格式. 格式如下: for(数据类型 变量:集合) 语句块 接下来看一个例程: ...

  2. C++11 中值得关注的几大变化(网摘)

    C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...

  3. C++11 中值得关注的几大变化(详解)

    源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里. ...

  4. STL中mem_fun, mem_fun_ref用法

    1.引言 先看一个STL中for_each的用法: #include <iostream> #include <vector> #include <algorithm&g ...

  5. C++ 11 之Lambda

    1.Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包”,如果 lambda 函数没有传回值(例如 void ),其回返类型可被完全忽略. 定义在与 lambda ...

  6. 【现代程序设计】【homework-07】

    C++11 中值得关注的几大变化 1.Lambda 表达式 Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包”,如果 lambda 函数没有传回值(例如 void ...

  7. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  8. 记录 C++ STL 中 一些好用的函数--持续更新 (for_each,transform,count_if,find_if)

    在日常的编程中,有这么几种操作还是比较常见的: 把一组数据都赋值成一个数,在一组数据中查找一个数,统计一组数据中符合条件的数等等. 一般的写法可以用循环,没有什么是循环不能搞定的.假如在这里怎么用介绍 ...

  9. 45 孩子们的游戏(圆圈中最后剩下的数) + list操作总结+ for_each多记忆容易忘记

    题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机指 ...

随机推荐

  1. hibernate注解方式来处理映射关系

    在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,我在试了这两种方式 ...

  2. C# Selenium学习

    https://blog.csdn.net/hjkl950217/article/details/54314760 https://www.cnblogs.com/vaevvaev/p/7041842 ...

  3. spring boot @Value Could not resolve placeholder

    @Configuration public class PropertySourcePlaceholderConfig { @Bean public PropertySourcesPlaceholde ...

  4. Linux命令(十一)gcc

    1. gcc -E 预处理 头文件展开 宏替换 2. gcc -S: 生成汇编指令 3. gcc - c: 生成二进制文件 4. gcc -I: (包含头文件) 5. gcc -o: 指定输出 6. ...

  5. Centos配置ARP和Tomcat Native

    Tomcat Native是用于Tomcat的一个可选组件,能够允许Tomcat使用一定的本地资源.性能.兼容性. 具体来说,Tomcat Native给了Tomcat访问 Apache Portab ...

  6. Silverlight用户无法注册之MySql.Data.dll不一致

    本篇博文记录本人解决一个"用户无法注册"的问题的过程 1 问题描述: 用户可以删除:但不能注册,也不能修改权限: 图 1用户注册失败 图 2修改用户权限出错 2 解决过程 1)粗暴 ...

  7. vue 组件动态 循环

    组件可以是动态的,记录如下 <div v-for="item in arrComponent"> <component v-bind:is="item. ...

  8. vivalidi 一款由Web技术诞生的Web浏览器

    vivalidi https://vivaldi.com/ A million ways to customize everything The world is a colorful place b ...

  9. oracle 启动em (使用浏览器打开)

    在cmd命令中执行 emctl status dbconsole 如果报错,确实oracle_UNQNAME 这个时候需要设置变量 oracle_hostname 和oracle_unqname 执行 ...

  10. scrapy框架的每个模块的用途

    ## 一.scrapy框架的每个模块的用途 1.spiders: 自定义爬虫 定义允许爬取的范围 定义开始爬取的url parse:一定要重写 start_request:一般不需要重写,可以通过重写 ...