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.
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, whereN
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 asmake_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); }
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.
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.
- 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.