There is a very nice present for those who like std::pair. Boost has a library called Boost.Tuple. It is just like std::pair, but it can also work with triples, quads, and even bigger collections of types.
Combining multiple values into one
Getting ready
Only basic knowledge of C++ and a standard library is required for this recipe.
How to do it...
Perform the following steps to combine multiple values into one:
- To start working with tuples, you need to include a proper header and declare a variable:
#include <boost/tuple/tuple.hpp>
#include <string>
boost::tuple<int, std::string> almost_a_pair(10, "Hello");
boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1);
- Getting a specific value is implemented via the boost::get<N>() function, where N is a zero-based index of a required value:
#include <boost/tuple/tuple.hpp>
void sample1() {
const int i = boost::get<0>(almost_a_pair);
const std::string& str = boost::get<1>(almost_a_pair);
const double d = boost::get<2>(quad);
}
The boost::get<> function has many overloads and is used widely across Boost. We already saw how it can be used with other libraries in the Storing multiple chosen types in a container/variable recipe.
- You can construct tuples using the boost::make_tuple() function, which is shorter to write, because you do not need to fully qualify the tuple type:
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <set>
void sample2() {
// Tuple comparison operators are
// defined in header "boost/tuple/tuple_comparison.hpp"
// Don't forget to include it!
std::set<boost::tuple<int, double, int> > s;
s.insert(boost::make_tuple(1, 1.0, 2));
s.insert(boost::make_tuple(2, 10.0, 2));
s.insert(boost::make_tuple(3, 100.0, 2));
// Requires C++11
const auto t = boost::make_tuple(0, -1.0, 2);
assert(2 == boost::get<2>(t));
// We can make a compile time assert for type
// of t. Interested? See chapter 'Compile time tricks'
}
- Another function that makes life easier is boost::tie(). It works almost as make_tuple, but adds a nonconst reference for each of the passed types. Such a tuple can be used to get values to a variable from another tuple. It can be better understood from the following example:
#include <boost/tuple/tuple.hpp>
#include <cassert>
void sample3() {
boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1);
int i;
float f;
double d;
int i2;
// Passing values from 'quad' variables
// to variables 'i', 'f', 'd', 'i2'.
boost::tie(i, f, d, i2) = quad;
assert(i == 10);
assert(i2 == 1);
}
How it works...
Some readers may wonder why we need a tuple when we can always write our own structures with better names; for example, instead of writing boost::tuple<int, std::string>, we can create a structure:
struct id_name_pair {
int id;
std::string name;
};
Well, this structure is definitely clearer than boost::tuple<int, std::string>. The main idea behind the tuple's library is to simplify template programming.
There's more...
A tuple works as fast as std::pair (it does not allocate memory on a heap and has no virtual functions). The C++ committee found this class to be very useful and it was included in the standard library. You can find it in a C++11 compatible implementation in the header file <tuple> (don't forget to replace all the boost:: namespaces with std::).
The standard library version of tuple must have multiple micro optimizations and typically provides a slightly better user experience. However, there is no guarantee on the order of construction of tuple elements, so, if you need a tuple that constructs its elements starting from the first, you have to use the boost::tuple:
#include <boost/tuple/tuple.hpp>
#include <iostream>
template <int I>
struct printer {
printer() { std::cout << I; }
};
int main() {
// Outputs 012
boost::tuple<printer<0>, printer<1>, printer<2> > t;
}
The current Boost implementation of a tuple does not use variadic templates, does not support rvalue references, does not support C++17 structured bindings, and is not usable with constexpr.
See also
- Boost's official documentation contains more examples, information about performance, and abilities of Boost.Tuple. It is available at the link http://boost.org/libs/tuple.
- The Converting all tuple elements to a string recipe in Chapter 8, Metaprogramming, shows some advanced usages of tuples.