C++中实现foreach循环的示例

python,c#,java里面都有类似于foreach的结构,stl里面虽然有for_each这个函数,但是感觉使用还是太繁琐了一些,所以就自己实现了一个。 先来看看stl里面的for_each函数,官方文档上的原型如下:

Function for_each (InputIterator first, InputIterator last, Function f);

示例代码如下:

// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
 
void myfunction (int i) {
  cout << " " << i;
}
 
struct myclass {
  void operator() (int i) {cout << " " << i;}
} myobject;
 
int main () {
  vector<int> myvector;
  myvector.push_back(10);
  myvector.push_back(20);
  myvector.push_back(30);
 
  cout << "myvector contains:";
  for_each (myvector.begin(), myvector.end(), myfunction);
 
  // or:
  cout << "\nmyvector contains:";
  for_each (myvector.begin(), myvector.end(), myobject);
 
  cout << endl;
 
  return 0;
}
不只函数原型有点不习惯,而且还要再写一个函数,比起python的实现方式,的确有点繁琐了:

for d in l:
    print d

我们来自己实现一个,方法肯定是用宏啦,我们来看一下第一个版本:

#define foreach(container,it,type) \
    for(type::iterator it = (container).begin();it!=(container).end();++it)

示例代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;
 
#define foreach(container,it,type) \
    for(type::iterator it = (container).begin();it!=(container).end();++it)
 
int main(int argc, const char *argv[])
{
    set<string> s;
    s.insert("w");
    s.insert("a");
    s.insert("n");
 
 
    foreach(s,it,set<string>)
    {
        cout<<*it<<endl;
    }
 
    /*map<unsigned,string> m;
    m[0]="x";
    m[1]="w";
 
    foreach(m,it,map<unsigned,string>)
    {
        cout<<it->first<<","<<it->second<<endl;
    }*/
 
    return 0;
}

如果把注释掉的代码打开的话,就会报错,应该是宏无法处理逗号的原因。
而且调用起来还是有点繁琐对吧,python里面并没有要求传入容器类型,我们是不是也能把set这个参数省掉呢?
先来看一下这段代码:

typeof(10) a;
a = 100;
cout<<a<<endl;
这段代码是可以执行的,运行结果是100。从这一点出发,我们是不是能通过typeof(container)获得容器类型,然后通过typeof(container)::iterator创建遍历指针呢,我们来看第二个版本

#define foreach(container,it) \
    for(typeof(container)::iterator it = (container).begin();it!=(container).end();++it)
然而很不幸,这段代码是无法运行的,编译结果如下:

test4.cpp|21| error: expected initializer before "it"
test4.cpp|21| error: `it' was not declared in this scope
test4.cpp|34| error: expected initializer before "it"
test4.cpp|34| error: `it' was not declared in this scope
有没有办法解决呢?
有的,我们用一个曲线救国的方法!typeof(container.begin()) ,哈哈!最终代码如下:

#define foreach(container,it) \
    for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)
测试代码如下:

#include <vector>
#include <set>
#include <map>
using namespace std;
 
#define foreach(container,it) \
    for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)
 
int main(int argc, const char *argv[])
{
    set<string> s;
    s.insert("w");
    s.insert("a");
    s.insert("n");
 
 
    foreach(s,it)
    {
        cout<<*it<<endl;
    }
 
    map<unsigned,string> m;
    m[0]="x";
    m[1]="w";
 
    foreach(m,it)
    {
        cout<<it->first<<","<<it->second<<endl;
    }
 
    return 0;
}
输入结果如下:

a
n
w
0,x
1,w
OK!一切正常!这应该是形式比较简单的版本啦,如果各位有什么更好的建议,欢迎留言交流~
ps:
当然,其实你连it这个参数都可以省掉,但是根据pythonic的原则(好吧,我知道自己是在写C++),要简单但不能让人迷惑,所以建议还是把it这个参数保留。

补充:

假有一个类型为ContainerType类型的容器Container,它的每个元素的类型为ElementType。
在C#中,数组就是这样一种容器。
在C++中,stl的vector、map等也是这样的容器。
如果要遍历容器Container的每个元素,在C#中可以使用如下代码:
foreach ( ElementType element  in  Container)
{  //  使用element访问该元素
}
而在C++中,通常的代码都会是这样:
Container::iterator iter;
for  (iter  =  Container.begin(); iter != Container.end(); iter ++ )
{  //  使用(*iter)访问该元素
}

显然C#中的代码更清晰的多。而C++的代码中包含了变量声明和循环控制,显得更复杂了。也许您对这一点增加的复杂性并不在意,但本着勿因善小而不为的原则,以及一点思考精神,我决定让C++也拥有使用foreach循环的能力。
 
C++的宏很适合做这种事情。问题在于如何做的更像C#中的那种样式。如果在访问元素的代码块的前面和后面各加一个宏,那么这件事情就变得毫无意义,并很可笑。
 
我们只能使用一个宏,并命名为foreach。在这个宏后面的代码块将可以像在C#中那样可以使用一个变量名来遍历容器中的所有元素。宏中声明的变量不能污染到程序中其它部分的命名间,而这些变量又不在访问元素的代码块中声明。这样的要求使这个问题变成一种考验代码技巧的有趣问题。
 
C++语言控制能力的强大使它确实可以支持foreach语句。这要用到两个技巧:1,for循环的第一条语句可以声明局部变量;2,充分利用for循环的过程控制能力。
 
C++中的foreach语句定义宏如下:  
#define foreach(elementType, element, containerType, container) /
     for  (containerType::iterator iter  =  container. begin (); iter  !=  container. end (); iter ++ )/
         for  (bool  go   =  true;  go ;)/
             for  (elementType  &  element  =   * iter; go ;  go = false)
宏中定义了三重for循环。第一重的意义很清楚:使用容器的遍历者遍历容器中的元素。第二、第三重for循环其实只能执行一次,其主要目的是声明element变量。C++的变量引用类型使后面的元素访问代码块可以直接使用element变量。
 
foreach 宏的参数依次为:元素类型,元素名,容器类型,容器名。
 
假设有个vector如下面的定义:
vector<int > v;
 
那么遍历v可以使用下面的代码:
foreach(int , e, vector<int >, v)
{// 使用(e)来访问v的元素
}
 
是不是很像C#中的foreach语句呢?我写了一小段程序,看看这个宏是不是真的能工作,代码如下:

#include <iostream>
#include <vector>
using namespace std;
 
// 在C++中使用 foreach 循环
#define foreach(elementType, element, containerType, container) /
    for (containerType::iterator iter = container.begin(); iter != container.end(); iter++)/
       for (bool go = true ; go;)/
           for (elementType & element = *iter;go; go=false )
 
int main()
{
    vector<int > v;
    for (int i=0; i<10; ++i)
       v.push_back(i);
    foreach(int , e, vector<int >, v) // 在这里使用foreach 语句
    {
       printf("%d/n", e);
    }
}
 
结果输出很正确!
 
事实上,在C++中,for语句以及其它语句,它们的本质是基于计算机指令的过程控制语句,而C#中的foreach语句,可以看作是基遍历者这种设计模式的语句。编程语言从只基于计算机指令到基于设计模式,这应该也算是软件发展的进步吧。
 
在C++中使用文中定义的foreach语句并不能提高程序的效率,也不会明显降低效率。foreach宏只能在代码层面上有些好处,减少一些重复的代码,增加一点可读性。设计这个宏,就当是个趣味技巧题,玩一玩,并支持一下那些坚决拥抱C++的朋友们。

 

时间: 2024-07-28 16:03:26

C++中实现foreach循环的示例的相关文章

详解JAVA中的for-each循环与迭代_java

在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable<T>接口(位于java.lang包中),实现这个接口允许对象成为 "foreach" 语句的目标,而此接口中的唯一方法,实现的就是返回一个在一组 T 类型的元素上进行迭代的迭代器. 一.迭代器Iterator 接口:Iterator<T> public interface Iterator<E>{ boolean hasNext

深入理解java中for和foreach循环_java

•for循环中的循环条件中的变量只求一次值!具体看最后的图片 •foreach语句是java5新增,在遍历数组.集合的时候,foreach拥有不错的性能. •foreach是for语句的简化,但是foreach并不能替代for循环.可以这么说,任何foreach都能改写为for循环,但是反之则行不通. •foreach不是java中的关键字.foreach的循环对象一般是一个集合,List.ArrayList.LinkedList.Vector.数组等. •foreach的格式: for(元素类

Java for-each循环使用难题2例(高级使用方法)_java

Java中,for-each循环简化了任何Collection或array的遍历过程,但并不是每个Java程序员都了解本文将要描述的for-each 循环的一些细节.与 Java5 发布的其他术语:释放别名泛型,自动封装和可变参数不同,Java开发者对for-each循环的使用比任何其他特性更加频繁,但当问及高级的for-each循环怎样工作,或什么是在for-each循环中使用Collection时的基本需求时,就不是每个人都能够回答的了. 本篇教程和例子旨在通过深入研究for-each 循环

遍历-求大神指点 关于java 的foreach循环问题

问题描述 求大神指点 关于java 的foreach循环问题 import java.util.Arrays; public class lianxi02 { public static void main(String[] args) { // 定义一个整型数组,保存成绩信息 int[] scores = { 89 72 64 58 93 }; // 对Arrays类对数组进行排序 Arrays.sort(scores); // 使用foreach遍历输出数组中的元素 for (int sco

smarty手册-smarty中foreach循环语句详解

原文地址:smarty手册-smarty中foreach循环语句详解作者:谭博 {foreach}循环也有自身属性的变量,可以通过{$smarty.foreach.name.property}访问,其中"name"是name属性. Note: The name attribute is only required when you want to access a {foreach} property, unlike {section}. Accessing a {foreach} p

mysql-jsp页面中c:forEach从数据库循环出的多个name的值如何传递到servlet中并写入数据库

问题描述 jsp页面中c:forEach从数据库循环出的多个name的值如何传递到servlet中并写入数据库 我的四种题目是来自四个表中 都是自增列 但是在jsp提取的相应题目号不是顺序+1的 <h1> 单选题:</h1><br> <c:forEach items=""${Indivlist}"" var=""ind""> ${ind.question}<br> &

foreach循环中遍历五个对象之后换行,换行判断怎么写

问题描述 foreach循环中遍历五个对象之后换行,换行判断怎么写 原价:${cloth['costPrice']}元 现价:${cloth['price']}元点击进入 /c:forEach 载我的源代码上面添加,谢谢 解决方案 你的代码在哪里??? 解决方案二: 没有找到你的代码,给你个例子吧. String[] names=new String[]{"a","b","c","d","e","

Java中遍历数组使用foreach循环还是for循环?_java

从JDK1.5起,增加了新功能Foreach,它是for循环遍历数据的一种简写形式,使用的关键字依然是for,但参数格式不同.其详细用法为: for(Type e:collection){ //对变量e的使用} 参数说明: e:其类型Type是集合或数组中元素值的类型,该参数是集合或数组collection中的一个元素. collections: 要遍历的集合或数组,也可以是迭代器. 在循环体中使用参数e,该参数是foreach从集合或数组以及迭代器中取得的元素值,元素值是从头到尾进行遍历的.

php foreach循环中使用引用的问题_php技巧

看代码,再做解释 复制代码 代码如下: <?php $array=array('a','b','c','d'); foreach($array as $key=>$val){     //do something } echo $val;//输出d echo $kay;//输出3 $val='e'; print_r($array);//输出Array ( [0] => a [1] => b [2] => c [3] => d ) ?>  在foreach循环中,当