C++11 supports range-based for loops. This is a very convenient feature, can save quite a lot of code. The following code makes it easy to traverse the elements in the vector and print them out:
Std::vector<int> Int_vec;
Int_vec.push_back (1);
Int_vec.push_back (2);
If you want to modify the elements in Int_vec, declare the variable x as int& for
(int x:int_vec)
{
std::cout << x << endl;
}
The objects that can be traversed include:
Array (not including pointers)
• Defines the Begin () and end () methods, and returns the class object that the method returns the iterator. (All containers in the STL are OK)
(for the traversal of dynamically generated arrays, you can also save a lot of code with the range class described below)
For reference Http://en.cppreference.com/w/cpp/language/range-for,
Statement for (Range_declaration:range_expression) loop_statement
is equivalent to the following statement:
{
auto && __range = range_expression;
for (Auto __begin = begin_expr,
__end = end_expr;
__begin!= __end; ++__begin) {
range_declaration = *__begin;
Loop_statement
}
}
For class objects that can be traversed, __begin and __end are generated by the begin () and end () methods of the class respectively. And because the __range variable is a right value reference, if the range_expression result is a right value, it will be refactored after the loop ends.
--------------------------------------------------------------------------------
In this way, C++11 finally supports the traversal approach that is supported by this modern programming language. However, both the syntax and the standard library do not support traversal of specific numbers, such as in the for-I in xrange (1,5) statement in Python, where X will continuously take the value in [1,4]. (The Boost library has irange classes to meet this requirement, but I'll discuss the implementation below)
The most straightforward approach is to write a function that returns a Vector<int> object whose elements are values from begin to end. However, it is necessary to construct one of these objects each time the loop is a bit slow.
From the standard point of view, if a class is to support such traversal, there must be at least the Begin () and end () methods. In the initialization section of the for loop, after the two methods are invoked, there is no such thing--it's an iterator. So it's natural to start with the iterator. This iterator must support three kinds of operations:!=, prefix + +, dereference
。 If this "iterator" is a value of int, the __begin!=__end;++__begin statement in the loop above is a very natural implementation. The goal now is simple: the iterator does not traverse each element in the container, but is a simple encapsulation of the int value. The dereference will return this number
, and both comparison and self operation operate on this number.
--------------------------------------------------------------------------------
When you have an idea, it's easy to make it happen. First, you define an imitation iterator fakeiter, which encapsulates a numeric value and overloads the required operators.
Class Fakeiter
{
typedef long _VTYPE;//The type of numeric value is long. Of course, you can write a template. Public
:
explicit Fakeiter (_vtype val)
: Value_ (val) {}
bool operator!= (const fakeiter & other) const
{return
(This->getvalue ())!= (the other. GetValue ());
}
_vtype operator* () const
{return
GetValue ();
}
Const fakeiter& operator++ ()
{
++value_;
return *this;
}
Private:
_vtype GetValue () const
{return
value_;
}
_vtype value_;
};
The implementation of the "container" class is simpler: Implement the Begin () and end () methods and return the Fakeiter above. The method in the class adds a few cout statements to better understand the invocation process of the specific method when the loop executes, and can be deleted when it is actually used.
Class Range
{
typedef long _VTYPE;//Also, you can get a template out, but it's inconvenient to use public
:
Range (_vtype begin_v, _vtype end_v )
: Begin_value_ (Begin_v), End_value_ (End_v)
{
cout<< "range::range ()" <<endl;
}
~range ()
{
cout<< "range::~range ()" <<endl;
}
Fakeiter begin () const
{
cout<< "range::begin ()" <<endl;
Return Fakeiter (Begin_value_);
}
Fakeiter End () const
{
cout<< "range::end ()" <<endl;
Return Fakeiter (End_value_);
}
Private:
_vtype begin_value_;
_vtype End_value_;
All right, try this one, it's useless:
for (auto X:range (1,5))
{
std::cout<<x<<endl;
}
std::cout<< "Loop End" <<endl;
The output under vs2012 and Clang is as follows:
Range::range ()
range::begin ()
range::end ()
1
2
3
4
range::~range (
) Loop End
Well, it would seem to work if the comments on the output statements that affect the line of sight are dropped. Now to iterate over a new-generated array, it's just a matter of a range subscript, and the world is quiet.
But, step size! Well, it looks like I don't have that kind of demand for a while. But the implementation is also very simple: Modify the Fakeiter class, you can add a member to represent the step size, and then modify the self operation. Further, you can add a generator method and become a more generic generator. With the c++11 lambda operator, it is also very convenient to use.
The above is a small series for everyone to bring the c++11 for the loop, as well as the range of the simple realization of the entire content, I hope that we support cloud Habitat Community ~