C++11 range-based for loop


In a normal for loop statement-inherited from C- we usually write three expressions separated by ‘;‘(semi-colon) to specify the condition of the iteration.The for statement iterates the specified number of times during which we perform various operations.But unlike the C98 ‘for statement’ C++11 introduced a new feature known as range-based for loop which allows iterating the for statement using a simpler syntax and expression.The general syntax of range-based for loop is.


for(declaration : expression )
{

}

declaration: This is usually a variable of the type from which we want to access the value.

expression:This is a name of the container or any equivalent storage from which we would access the value.

Link: for loop statement

Using range-based for loop with built-in type

Let us use a range-based for loop to access an array.

int arr[]={ 12 , 45 , 90};

for( int elem : arr )
{
cout<< elem << ” ” ;
}

Output

12 45 90

In the above code instead of specifying the type literally like the ‘int’ for ‘elem’ variable,we can use the C++11 feature ‘auto‘ and let the compiler specify the type for us automatically.So re-writting the above code using ‘auto’ the program is given below.

Link:C++11 auto

for( auto elem:arr )
{
cout<< elem << ” ” ;
}

Output

12 45 90

Here we have used ‘auto’ instead of ‘int’ and also using the range-based for loop we have accessed all the elements of the ‘arr’ array.I am sure this method is simpler than the traditional ‘for loop’ statement.





Using range-based for loop with STL containers

We can also use range-based for loop to access the content of the STL containers.Lets directly jump to the code example given below.

vector<string> vec={ “Sad” , “happy” , “anger” };

for(auto elem:vec)
{
cout<< elem << ” ” ;
}

Output

Sad happy anger

This is same as using the iterator to access the vector content in the for loop.

for(vector<string>::iterator elem=vec.begin( ) ; elem!=vec.end( ); elem++ )
{
cout<< *elem << ” ” ;
}

Output

Sad happy anger



Using reference as a declaration inside ranged-based for loop

Whenever you want to change the value of the array or collection of objects using the range-based for loop make sure that you use a reference instead of the normal declaration.Consider an example below which uses the normal declaration.

int arr[]={ 1 , 2 , 3 , 4 };

for( auto elem:arr )
{
elem=elem*elem ;
cout<< elem << endl ;
}

cout<< endl << arr[0] << ” ” << arr[1] ;

Output

1
4
9
16

1 2

Although the value is changed inside the for statement,the changes is not seen outside the for statement.Only the local variable ‘elem’ value is changed which has a local scope.

C++11 range-based for loop

The value of the array is copied to the elem storage as we iterate through the loop.So in fact we are accessing the value in elem storage not the actual value of the array.

Using reference

If we use a reference we are directly accessing the storage of the array,so the changes will be seen outside the for statement.Consider the code example given below.

for(auto &elem:arr )
{
elem=elem*elem ;
}

cout<< arr[0] << ” ” << arr[1] << ” ” << arr[2] << endl ;

Output

1 4 9

Use reference is you wish to change the value of the array or any container with range-based for loop.


 


When the data type is a class or struct

In class or struct array or a container holding class type,the range-based for loop can be implemented in the same way as the built-in type.Here in each iteration the variable will point to the object of the type.

class A
{
string st;

public:
A(string s):st(s) { }

string get() const { return st; }

~A( ) { }
};

int main( )
{
vector<A > vecA={ A(“He Man”) , A(“Thunder Cat”) , A(“Mummy”) };

for(auto elem:vecA)
{
cout<< elem.get() << endl ;
}

return 0;
}

Output

He Man
Thunder cat
Mummy

elem point to A object and we call get() to access the data member of the object.There is no new implementation here,it’s what we have been doing.

implicit conversion is not allowed in range-based for loop

If the constructor of the class accepts only explicit type than the declaration in the range-based for loop does not allow implicit conversion.Consider the code below.

class B
{
int i;

public:
B(int val):i(val) { }

int get() const { return i; }

~B( ) { }
};

int main( )
{
vector<int> vecI={12 , 4 , 40};

for( B &elem:vecI ) //error
{
cout<< elem.get();
}

vector<string> vecS={” 89″ , ” 2012 the end” };

for(A &elem:vecS) ///work fine
{
cout<< elem.get() ;
}

return 0;
}

In the first ‘for’ loop the constructor of B allows only explicit type.This provide constraint from converting the elements of vecI to B object type.However,in the second for loop there is no such restriction impose by the A constructor.Thus,vecS elements is converted to A object type.