Sunday 22 December 2013

STL Tuples

The STL tuple class is a bit like the STL pair, except the tuple supports any number of types to be tied together in a single object. This can be achieved using variadic templates, although many tuple implementations were completed before variadic templates were available (e.g. VC++ 2012). They implemented the tuple by using different macros for different numbers of arguments.


STL pairs are useful but sometimes not sufficient

STL pairs are useful when two pieces of data are always coupled together, for example:

std::pair<std::string, float> raceWinner{ "M40", 17.20 };

However, in the past, to include any more pieces of data required some more work, for example creating a simple struct or class:

struct triathlonResult {
std::string ageCategory;
float swim;
float cycle;
float run;
};

which (if uniform initialization is supported) can then be used with:

triathlonResult triathlonWinner{ "M35", 13.45, 35.5, 17.3 };

STL tuples extend the pair to any number of arguments

The introduction of the tuple to the standard library means that a custom class is no longer needed, instead:

std::tuple<std::string, float, float, float> triathlonWinner( "F35", 13.45, 35.5, 17.3 );

can be used to create an object that holds the same information.

Initialization can be simplified using auto and make_tuple like this:

auto triathlonWinner = make_tuple("F35", 13.45, 35.5, 17.3);

An added convenience is that the comparison operators (==, !=, >, >=, < and <=) are included in the standard library. From the standard [tuple.rel] - "The elementary comparisons are performed in order from the zeroth index upwards. No comparisons or element accesses are performed after the first equality comparison that evaluates to false".


Retrieving elements from a tuple

Retrieving elements from a tuple may differ from how you're used to getting them from a pair. One way to retrieve members from a pair is to use the public members first and second. For example:

auto raceWinnersCategory = raceWinner.first;
auto raceWinnersTime = raceWinner.second;

However, there is no tuple member function to retrieve elements, instead they must be retrieved using the non-member function get (defined in <tuple>). The reason is that the element to retrieve must be indexed, and if this were to happen on a member function it would need to be invoked using the template keyword like this:

auto triWinnersCategory = triathlonWinner.template get<0>();
(for more information see [tuple.helper] note 11 from the standard)

To avoid this a non-member get function is provided, to be used as shown:
auto triWinnersCategory = get<0>(triathlonWinner);
auto triWinnersSwimTime = get<1>(triathlonWinner);
auto triWinnersCycleTime = get<2>(triathlonWinner);
auto triWinnersRunTime = get<3>(triathlonWinner);

This may not seem very natural to code at first but it is easy to read. Note that this get function can also be used for pairs, so if you suspect your pairs may one day be promoted to tuples then it's a good idea to use get with pairs too.

No comments: