STL/Boost C++ 11 中foreach的用法

本篇将对C++ 标准库中的两种foreach,以及boost中的BOOST_FOREACH进行讲解说明

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <boost/foreach.hpp>

// 遍历STL标准库容器
int main()
{
	std::vector<int> vec{ 1,2,3,4,5 };

	// 1. C++ 中标准用法 
	for (int &num : vec)
	{
		num *= 2;
	}
	// 2. algorithm 中的 for_each
	std::for_each(begin(vec), end(vec), [](int num) {std::cout << num << " "; }); // 写法1
	std::cout << std::endl;

	std::for_each(vec.cbegin(), vec.cend(), [](int num) {std::cout << num << " "; });	// 写法2, 多一个c前缀表示const
	std::cout << std::endl;

	std::for_each(vec.rbegin(), vec.rend(), [](int num) {std::cout << num << " "; });	// 反向遍历,r前缀表示反向,r和c可以组合使用
	std::cout << std::endl;
	/*
	这种写法可能被废弃了,在VS2017下报错
	for each (object var in collection_to_loop)
	{

	}
	*/

	// 3.BOOST_FOREACH 
	// 与第1种用法类似 for(object var: collection_to_loop)
	BOOST_FOREACH(int &num, vec)	// 可以使用引用访问
	{
		num += 1;
	}

	int num;	
	BOOST_FOREACH(num, vec) // 可以将 int num 定义写在外边
	{
		std::cout << num << " ";
	}
	std::cout << "\n";		
	// 反向遍历
	BOOST_REVERSE_FOREACH(const auto & num, vec) // 可以写int num, auto num, const int num, int &num等,都没有问题
	{
		std::cout << num << " ";
	}

	std::cin.get();
	return 0;
}

以下是官方提供的 Range-based for Statement (C++) 示例代码

// range-based-for.cpp  
// compile by using: cl /EHsc /nologo /W4  
#include <iostream>  
#include <vector>  
using namespace std;  
  
int main()   
{  
    // Basic 10-element integer array.  
    int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  
  
    // Range-based for loop to iterate through the array.  
    for( int y : x ) { // Access by value using a copy declared as a specific type.   
                       // Not preferred.  
        cout << y << " ";  
    }  
    cout << endl;  
  
    // The auto keyword causes type inference to be used. Preferred.  
  
    for( auto y : x ) { // Copy of 'x', almost always undesirable  
        cout << y << " ";  
    }  
    cout << endl;  
  
    for( auto &y : x ) { // Type inference by reference.  
        // Observes and/or modifies in-place. Preferred when modify is needed.  
        cout << y << " ";  
    }  
    cout << endl;  
  
    for( const auto &y : x ) { // Type inference by reference.  
        // Observes in-place. Preferred when no modify is needed.  
        cout << y << " ";  
    }  
    cout << endl;  
    cout << "end of integer array test" << endl;  
    cout << endl;  
  
    // Create a vector object that contains 10 elements.  
    vector<double> v;  
    for (int i = 0; i < 10; ++i) {  
        v.push_back(i + 0.14159);  
    }  
  
    // Range-based for loop to iterate through the vector, observing in-place.  
    for( const auto &j : v ) {  
        cout << j << " ";  
    }  
    cout << endl;  
    cout << "end of vector test" << endl;  
}  

经过测试,将上边示例中for换成BOOST_FOREACH, for中的冒号换成逗号,发现程序仍然正常运行,说明两者是等价的。

下面列举一些BOOST_FOREACH的用法示例

1. 可访问std::string

#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

2.支持C风格的数组,下面是一些示例展示了BOOST_FOREACH的基本用法

#include <iostream>  
#include <vector>  
#include <boost/foreach.hpp>
#include <list>
#include <queue>
using namespace std;

void main()
{
	// 1. 访问STL容器
	std::list<int> list_int{ 1,2,3,4 };
	BOOST_FOREACH(int i, list_int)
	{
		// do something with i
	}

	// 2. 可以访问C风格的数组
	short array_short[] = { 1,2,3 };
	BOOST_FOREACH(int i, array_short)
	{
		// The short was implicitly converted to an int
	}

	// 3. int i可前向定义,BOOST_FOREACH 支持关键字continue,break,return
	std::deque<int> deque_int{ 4,5,6,1,7,8,2,9 };
	//std::deque<int> deque_int{ 4,5,6,1,7,8,0,9 };
	int i = 0;
	BOOST_FOREACH(i, deque_int)
	{
		if (i == 0) return;
		if (i == 1) continue;
		if (i == 2) break;
		std::cout << i << " ";
	}

	// 4. 引用访问C数组
	short array_short[] = { 1, 2, 3 };
	BOOST_FOREACH(short & i, array_short)
	{
		++i;
	}
	//  array_short[] = { 2, 3, 4 };

	// 5. 使用嵌套的BOOST_FOREACH, 此处可以发现,BOOST_FOREACH的大括号不是必须的
	std::vector<std::vector<int> > matrix_int;
	BOOST_FOREACH(std::vector<int> & row, matrix_int)
		BOOST_FOREACH(int & i, row)
		++i;

	// 6. 循环体中可以是一个函数,函数返回值是要遍历的容器
	extern std::vector<float> get_vector_float();
	BOOST_FOREACH(float f, get_vector_float())
	{
		// 注意:此处的 get_vector_float() 函数只会被调用一次
		// 可以这样测试:让函数get_vector_float()每一次调用都返回不一样的值
	}

	// 7. 反向遍历
	std::list<int> list_int( /*...*/);
	BOOST_REVERSE_FOREACH(int i, list_int)
	{
		// do something with i
	}


	std::cin.get();
}

有一点需要注意的是,有时候我们觉得BOOST_FOREACH写起来比较长,不方便,于是我们就定义了以下的宏来代替BOOST_FOREACH:

#define foreach   BOOST_FOREACH

于是有了下面的代码

#include <iostream>
#include <boost/foreach.hpp>

//using namespace boost;
#define foreach   BOOST_FOREACH

void main()
{
	int arr[]{ 1,2,3,4,5 };

	foreach(int i, arr)
	{
		std::cout << i << " ";
	}


	std::cin.get();
}

运行起来确实也没问题,但是官方推荐尽量使用下面的宏定义

#define foreach_         BOOST_FOREACH
#define foreach_r_       BOOST_REVERSE_FOREACH

因为在boost/foreach.hpp中foreach是一个namespace,有很多人宏都是用的 #define foreach  BOOST_FOREACH,这样可能会出问题,我测试了当我using namespace boost 后,程序仍然正确运行,但并不表示所有情况都正确,因为foreach是一个比较常用的关键词,比如在Qt 中也有foreach,这样在某些情况下可能会有未知的错误,所以推荐使用带下划线的foreach宏定义

// boost/foreach.hpp
namespace foreach
{
    ///////////////////////////////////////////////////////////////////////////////
    // in_range
    //
    template<typename T>
    inline std::pair<T, T> in_range(T begin, T end)
    {
        return std::make_pair(begin, end);
    }

    //.....

} // namespace foreach

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章