C++ Tutorial: Use std::tuple To Simulate Compact Heterogeneous Containers

Introduction

Standard C++ programming containers classes such as vector and list are homogeneous, meaning they can store only one type of objects at a time. However, in some cases it's more convenient to use a container of heterogeneous objects, which is where std::tuple comes in handy. std::tuple can store up to 10 objects of different types.

Suppose you need to design a function that retrieves three values from a database: an index number representing the month of the year, and two floating point numbers that represent the consumer's price index (CPI) of the relevant month, and the CPI of the previous month. Although you can split this function into two, it's more efficient and convenient to have one function that retrieves these values in one shot. Your first step consists of defining a tuple type i.e, a specialization of the class template std::tuple. Here's an example:

  #include <tuple>
  using namespace std;
  
  typedef tuple <int, double, double> CPIs;

Here's the function declaration:

  CPIs get_cpis(const Date& d);

In the absence of explicit initializers for the tuple's elements, the elements will be default-initialized:

  tuple <double, char> t2(3.55, 'a');// explicit 
  tuple <double, int, string> t3; // <0.0,0,string()>

Helper Functions

The Standard Library defines meta-functions and helper functions for handling tuples conveniently. Meta-functions use template meta-programming to compute their results at compile time. Helper functions are free-standing functions with short and intuitive names. Let's look at some of these.

To get the number of elements that a tuple type has, use the tuple_size() meta-function:

  #include <tuple>
  using namespace std;
  
  int elements=tuple_size<CPIs>::value;//3

To automate the creation of a tuple object, use the make_tuple() helper function. make_tuple() deduces the types of its arguments to create a tuple type. It returns a tuple object initialized with those arguments:

  CPIs mycpi=make_tuple(2, 0.1, 0.3);

To get the type of a tuple element, use the tuple_element() meta-function. This function is useful for traversing a tuple or when you want to create copies of a tuple's elements without knowing the elements' types in advance. tuple_element() takes an index and the tuple type (remember that tuples use zero-based indexing). In the following example, tuple_element() retrieves the type of the first tuple element. The result is used for declaring val, an object whose type is the same as that of the tuple's first element:

  tuple_element <0, tuple<int, int, char> >::type val;//int

What if you need to access the actual value of a tuple element rather than its type? Use the get<n> function template. Get takes an index and returns the corresponding element's value. The following listing uses tuple_element() to declare objects of the types of a tuple object's elements and then calls get<n> to copy their corresponding values:

  CPIs cpi=make_tuple(4, 0.1, -0.2);
  tuple_element <0,CPIs>::type val1;//int
  tuple_element <1,CPIs>::type val2;//double
  tuple_element <2,CPIs>::type val3;//double
  
  val1=get<0> (mycpi);//4
  val2=get<1> (mycpi);//0.1
  val3=get<2> (mycpi);//-0.2

Putting it all Together

Suppose you're designing a stock quote search engine that accepts a free text query. The engine retrieves the current stock price along with the stock's symbol. To represent the stock prices, you use a pair of integral values for the dollars and cents (a pair of integers rather than double guarantees accurate comparisons among other things), and a string for the stock symbol. You can represent the stock price like this:

  typedef tuple<int,int,string> StockPrice1;

This design is simple but not descriptive enough -- the reader has to guess that the first two integers are construed as a pair. An alternative design would use a layered structure:

  typedef tuple<int,int> Currency;
  typedef tuple<Currency, double, string > StockPrice2;

Regardless of your favorite representation, both designs exhibit the beauty of tuples. For example, to compare two StockPrice records you don't need to overload any operators. std::tuple already includes the relevant overloaded operators for you:

  StockPrice1 get_quote(const string& query);
  StockPrice1 a(620,24,"GOOG");
  StockPrice1 b=get_quote("Google Inc.");
  if (a!=b) //is it the same quote?
...

As an aside, you're probably wondering why I didn't use std::pair to represent Currency. The truth is that a pair is nothing but a tuple containing two members. Historically, std::pair inspired the authors of std::tuple to design a more generalized notion of a fixed-size heterogeneous container. Of course, it doesn't mean that you're advised to avoid std::pair;

Conclusion

Tuples were added to C++ programming as part of the Standard Library Technical Report One (TR1 for short) which is a fancy name for what would otherwise be dubbed a service pack for the C++98 Standard Library. Virtually, every standard-compliant C++ compiler supports std::tuple today. Additionally, tuples (as all other TR1 features) are highly portable, so you can use them without hesitation in cross-platform code.

The main advantage of std::tuple is automation. Instead of inventing a heterogeneous container on your own, std::tuple will be convenient so long as you don't need more than 10 elements and don't expect to insert or remove elements dynamically.

Related Articles



Comments

  • Oakley Sunglasses Stores

    Posted by gogogis on 05/14/2013 01:39pm

    I love your blog.. very nice colors & theme. Did you create this website yourself or did you hire someone to do it for you? Plz respond as I'm looking to design my own blog and would like to find out where u got this from. thanks a lot Abercrombie Fitch Garments Come In A Range Of Colors and Designs ray ban canada Oakley Sunglasses Famous For Its Quality and Innovation

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Live Event Date: December 18, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this upcoming webcast …

Most Popular Programming Stories

More for Developers

RSS Feeds