STL/Boost C++ 11 中foreach的用法
阿新 • • 發佈:2019-02-15
本篇將對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