Dave
Assistant Engineer
Assistant Engineer
  • UID627
  • Fans3
  • Follows0
  • Posts55
Reads:2161Replies:0

A quick tutorial of standard library in the C++11 era (1) - a simple list composed by different type

Created#
More Posted time:Nov 8, 2016 9:29 AM
A simple list composed by different types of values - pair and tuple
A value pair is a simple list structure composed by two or more values of different types. The reason why we stress on “different types” is that values of the same type can be directly structured as an array.
The simplest value pair contains only two values. We call such a structure std::pair.
A pair with two values: std::pair
What is the point of such a simple structure? The point is being simple.
In many cases, what we want is being simple.
1. Key-value combination: For example, we want to place a key-value pair in a real container - this is a pretty common demand. It is beneath you to write a new class for every such combination, or use a complicated container. It would be most convenient if a simple value pair template class is in place.
2. Function returned value: C programmers may envy other languages very much, such as Go language or many script languages in which multiple values can be returned. The most common usage is to return an error code first, and then return the true values.
In the C++ template library, it is the case indeed.
An example of the first case is the map structure in the C++ standard library. Every element of map and multimap is a pair object.
When more than one value needs to be returned, such as the insert function of Set, a pair is returned.
Structure of pair
The simplest pair constructing is to use the make_pair function:
auto test1 = std::make_pair(1,"test1");
    auto test2 = std::make_pair(2,"test2");


The auto keyword of C++11 plays its role. We don't even need to write the std::pair template definition. Just construct a pair using std::make_pair and leave the type identification work to auto.
Let's look at another example of the function returned value:
std::pair<int,std::string> checkValue(int value){
    if(value<1000){
        return std::make_pair(0, "checked pass");
    }else{
        return std::make_pair(-1, "checked failed");
    }
}


Use of pair
The pair is easy to use. You can access the first and second values of an object through pair.first and pair.second.
For example, the function returned values in the example above can be processed like this:
auto result = checkValue(100);
    if(result.first==0){
        std::cout << "Checked pass! The message is: "<<result.second <<"\n";
    }


More than three values: std::tuple
The pair only applies to two values. What should we do when we need more than two values? C++11 presents us another big gift: C++11 supports templates to designate no specific number of parameters. So the restriction that C++98 can only support 10 parameters is lifted. Now tuple can support multiple parameters.
Std::get<0> Such syntax looks redundant for the pair, but it will be ready to demonstrate its prowess for tuple.
In a word, tuple is to expand the two parameters for a pair to three or more.
For example, if we want to add several more values in the function returned values, just replace pair with tuple and replace make_pair with make_tuple. Everything else can follow the existing routines.
std::tuple<int, std::string, std::string,int> checkValueWithDetails(int value){
    if(value<1000){
        return std::make_tuple(0,"checking passed","normal case",value);
    }else{
        return std::make_tuple(-1,"checking failed","bad case",value);
    }
}


To use the returned values, you still call the get<>() function. Of course, the first and second do not make any sense at this time, and get<>() should be used uniformly:
auto result3 = checkValueWithDetails(1);
    if(std::get<0>(result3)==0){
        std::cout<< "Checking passed! The message is: "<<std::get<1>(result3) << "The detail info is:" << std::get<2>(result3)<<"\n";
    }


std::tie batch processing
If we want to retrieve the tuple values and assign them to various variables, it is too much trouble to call get<> every time. Is there a one-off solution?
Of course there is. We can utilize the std::tie function.
auto result4 = checkValueWithDetails(-1);
    int resultValue;
    std::string message;
    std::string details;
    int initValue;
    std::tie(resultValue,message,details,initValue)=result4;


Does it feel like a script language in writing?
If we want to ignore some of the values, std::ignore can be used to hold the place, like “_” in the Go language, so that we don't need to define useless variables. For example, in the case above, if we are not interested in the message, we can write it like this:
std::tie(resultValue,std::ignore,details,initValue)=result4;

Std::ignore applies to any types.
To sum up:
1. The std::pair is a feature of C++98 and the std::tuple is a new feature in TR1. Two features of C++11 are very helpful for pair and tuple. One is auto type inference which helps us to write less code, and the other is C++11’s support of templates with changing parameters, which enables the support for any numbers of parameters theoretically. Tuple comes from the boost library. But without the support of C++11, the boost::tuple and std::tuple of TR1 can only support a limited number of parameters.
2. We can conveniently construct pair and tuple objects through std::make_pair and std::make_tuple.
3. Std::tie() function can be used to bind values in a pair or a tuple to some variables, and std::ignore can be used to ignore values of less concern.
Guest