C ++ 11 learning notes range-based for loop, learning notes
I.Introduction to a range-based for Loop
In C ++ 03/98, different containers and arrays have different traversal methods and different writing methods. C ++ 11 uses a range-based for loop for unification, it is easier to use a simple way to traverse containers and arrays.
Array loop:
1 using namespace std;2 3 const int size = 5;4 int* p = new int[size]{1,2,3,4,5};5 for(int i =0;i<size;i++){6 cout<<p[i]<<" ";7 }
Container loop:
1 using namespace std;2 3 vector<int> vec;4 for (auto it=vec.begin(),it!=vec.end();it++){5 cout<<*it<<" ";6 }
Of course, <algorithm> also has a for_each algorithm that can be used to traverse containers.
Function for_each( InputIterator begin, InputIterator end, Function f ) { while ( begin != end ) f( *begin++ );}
1 using namespace std;2 3 void do_cout(int& num){4 cout<<num<<" ";5 }6 7 vector<int> vec;8 for_each(vec.begin(),vec.end(),do_cout);
For_each
Advantage: you no longer need to pay attention to the Iterator concept.
Disadvantage: the start and End of the container must be displayed)
The range-based for statement is finally available in C ++ 11 ).
1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 int main(){ 7 vector<int> arr = {1, 2, 3}; 8 for(auto n : arr){ 9 cout << n << endl;10 }11 12 return 0;13 }
In the above range-based for loop, after the definition of n, followed by a colon (:), and then directly write the expression to be traversed, The for loop will automaticallyContainer returned by expressionIteration for Range
Note:
1. In the above example, we are all usingTraverse containers in read-only mode. If you need to modify the value in the container during the time period, you need to use the reference as follows.
1 for ( auto& n : arr){2 cout<< n++ << endl;3 }
2. You can useConst auto &To define the n type. In this way, you can traverse container elements (such as an std: vector <std: string> array) with a high replication workload without loss.
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 5 using namespace std; 6 7 int main(){ 8 vector<string> arr={"li ming","wang lei","han meimei"}; 9 for(const auto& n : arr){10 cout<<arr<<endl;11 }12 return 0;13 }
Ii. Usage Details of a range-based for Loop
1.
1 #include <iostream> 2 #include <map> 3 4 using namespace std; 5 6 int main(){ 7 map<string,int> ma={ 8 {"1",1},{"2",2},{"3",3} 9 };10 for(auto & val : mm){11 cout<< val.first <<"->" << val.second <<endl;12 }13 return 0;14 }
1). In a for loop, val is of the std: pair type. Therefore, for map-related containers, val. first or val. second is used to extract key values.
2). auto-pushing is the value_type in the container rather than the iterator.
2.
1 #include <iostream> 2 #include <set> 3 4 using namespace std; 5 6 int main(){ 7 set<int> se = {1 , 2, 3}; 8 for (auto& val : ss){ 9 //error:increment of read-only reference 'val'10 cout<< val++ << Lendl;11 }12 return 0;13 }
When using a range-based for loop, pay attention to the constraints of the container itself.
1 ). in this example, auto & defines the reference of the element in std: set <int>. You want to modify the set value in the loop, but std :: the internal elements of the set are read-only. Therefore, auto & in the for loop will be deduced as const int &.
2) In the std: map traversal, the std: pair reference in the for Loop Based on the range is not allowed to modify the first.
3.
1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 vector<int> arr = { 1, 2, 3, 4, 5}; 7 8 vector<int>& get_range(){ 9 cout<<"get_range ->: "<< endl;10 return arr;11 }12 13 int main(){14 for(auto val : get_range()){15 cout<< val << endl;16 }17 return 0;18 }
Output result:
Get_range->:
1
2
3
4
5
1). As shown in the preceding example, no matter how many times the range-based for loop iterates, the expression after the colon will only be executed once and will only be called before the first iteration.
4. A common for loop equivalent to a range-based for loop is as follows:
1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 int main(){ 7 vector<int> arr = {1, 2, 3, 4, 5}; 8 9 auto && __range = (arr);10 for( auto __begin = __range.begin(), __end = __range.end();__begin!=__end;++__begin(){11 auto val = *__begin;12 cout<< val <<endl;13 arr.push_back(0);14 }15 return 0;16 }
1 ). the range-based for loop is actually the syntax sugar of the common for loop. From the code above, we can clearly see that it is different from the traversal container we usually write, range-based for loop tends to determine the scope of iteration before the loop starts, rather than calling arr once before each iteration. end ().
3. Enable the range-based for loop to support custom types
The vector, set, and map mentioned above are all containers in the standard template library. All implement functions such as begin and end. So how can we make our own container class support range-based? The following is an example in the book.
1 // implementation of the iterator class 2 3 namespace detail_range {4 5 template <typename T> 6 class iterator 7 {8 public: 9 using value_type = T; 10 using size_type = size_t; 11 12 iterator (size_type cur_start, value_type begin_val, value_type step_val) 13: cursor _ (cur_start), step _ (step_val), value _ (begin_val) {14 value _ + = (step _ * cursor _); 15} 16 17 value_type operator * () const {18 return value _; 19} 20 21 bool operator! = (Const iterator & hrs) const {22 return (cursor _! = Rhs. cursor _); 23} 24 25 iterator & operator ++ (void) // prefix ++ operator only26 value _ + = step _; 27 ++ cursor _; 28 return (* this); 29} 30 31 private: 32 size_type cursor _; 33 const value_type step _; 34 value_type value _; 35}; 36 37} // namespace detail_range
C ++ 11: the alias of the template can only be using. It is no different from typedef when defining general type aliases.
// Impl is a class similar to the container to be implemented. We define the basic concept that the container has to abstract namespace detail_range {template <typename T> class imply {public: using value_type = T; using reference = const value_type &; using const_reference = const value_type &; using iterator = const detail_range: iterator <value_type>; using condition = const detail_range :: iterator <value_type>; using size_type = typename iterator: size_type; impl (value_type begin_val, Value_type end_val, value_type step_val): begin _ (begin_val), end _ (end_val), step _ (step_val), max_count _ (get_adjusted_count () {} size_type size (void) const {return max_count _;} const_iterator begin (void) const {return {0, begin _, step _ };} const_iterator end (void) const {return {max_count _, begin _, step _};} private: const value_type begin _; const value_type end _; const value_type step _; const Size_type max_count _; size_type get_adjusted_count (void) const {if (step _> 0 & begin _> = end _) throw std :: logic_error ("End value must be greater than begin value. "); else if (step _ <0 & begin _ <= end _) throw std: logic_error (" End value must be less than begin value. "); size_type x = static_cast <size_type> (end _-begin _)/step _); if (begin _ + (step _ * x )! = End _) ++ x; return x ;};}// namespace detail_range
Max_count _ is the maximum number of iterations. You can call the get_adjusted_count function to obtain the validity of begin _, end _, and step.
1 template <typename T> 2 detail_range: imply <T> range (T end) {3 return {}, end, 1 }; // use the initialization list 4} 5 6 template <typename T> 7 detail_range: impl <T> range (T begin, T end) {8 return {begin, end, 1}; 9} 10 11 template <typename T, typename U> 12 auto range (T begin, T end, U step)-> detail_range :: impl <decltype (begin + step)> {13 using r_t = detail_range: impl <decltype (begin + step)>; 14 return r_t (begin, end, step); 15}
1 # include <iostream> 2 3 using namespace std; 4 5 int main () {6 cout <"range (15):"; 7 for (int I: range (15) {8 cout <"" <I; 9} 10 cout <endl; 11 12 cout <"range (2, 6 ):"; 13 for (auto I: range (2, 6) {14 cout <"" <I; 15} 16 cout <endl; 17 18 const int x = 2, y = 6, z = 3; 19 cout <"range (2, 6, 3):"; 20 for (auto I: range (x, y, z )) {21 cout <"" <I; 22} 23 cout <endl; 24 25 cout <"range (-2,-6,-3 ):"; 26 for (auto I: range (-2,-6,-3) {27 cout <"" <I; 28} 29 cout <endl; 30 31 cout <"range (10.5, 10.5):"; 32 for (auto I: range (10.5, 10.5) {33 cout <"<I; 34} 35 cout <endl; 36 37 cout <"range (35,27,-1):"; 38 for (auto I: range (35,27,-1 )) {39 cout <"" <I; 40} 41 cout <endl; 42 43 cout <"range (0.5,):"; 44 for (auto I: range (0.5, 0.1) {45 cout <"" <I; 46} 47 cout <endl; 48 49 cout <"range ): "; 50 for (auto I: range (8, 7,-0.1) {51 cout <" "<I; 52} 53 cout <endl; 54 55 cout <"range ('A', 'z'):"; 56 for (auto I: range ('A', 'z ')) {57 cout <"" <I; 58} 59 cout <endl; 60 61 return 0; 62} 63 64 // The example runs as follows: 65 // range (15): 0 1 2 3 4 5 6 7 8 9 10 11 12 13 1466 // range (2, 6 ): 2 3 4 567 // range (2, 6, 3): 2 568 // range (-2,-6,-3 ): -2-569 // range (10.5, 10.5): 10.5 11.5 12.5 13.5 14.570 // range (35, 27,-1 ): 35 34 33 32 31 30 29 2871 // range (2, 8, 0.5): 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.572 // range (8, 7, -0.1): 8 7.9 7.8 7.7 7.6 7.5 7.4 7.3 7.2 // range ('A', 'z '): a B c d e f g h I j k l m n o p q r s t u v w x y