devxlogo

Tackle Common Programming Tasks Using the New <tuple> Library

Tackle Common Programming Tasks Using the New <tuple> Library

he C++ standards committee is now working on updates and enhancements to the Standard Library. Tuple types are one of the recent additions to the standard. A tupleis a fixed size collection of heterogeneous objects. Tuple types are very powerful and can help you simplify several programming tasks.


How can you simulate multiple return types for a single function? How do you assign and compare multiple values simultaneously?


Use the library to define tuple objects and manipulate them.

Author’s Note: Thus far, my 10-Minute Solutions have relied solely on C++98 features that every decent compiler should support. However, the library isn’t included in your IDE’s Standard Library yet. Therefore, you will need to download this library from Boost if you wish to compile the code samples included here. Even if you’d rather not install new libraries on your computer, future releases of your compiler will support anyway.

Construction and Initialization
A tuple type is a specialization, or an instance, of the class template tuple. The current library supports tuples with 0-10 elements. Each element may have a different type. In the following example, t is defined as a tuple type that contains two elements of type int and double:

#include tuple  t(1, 3.14);

For the sake of brevity, I do not use qualified names. The actual namespace in which tuple and its helper functions are declared depends on the library you’re using. The Boost library declares them in boost::tuples. Standard C++ will declare them in std, as usual.

If you omit the initializers, default initialization will apply instead:

tuple <:string int> u; //initialized to: string(),0

Helper Functions
To obtain a tuple’s number of elements, use the tuple_size()function like this:

int sz=tuple_size  >::value;//3

The make_tuple()function facilitates the construction of tuple types. It creates a tuple type according to its arguments:

void f(int i);T1=make_tuple(&f); // returns: tupleT2=make_tuple("hi", 2); // tuple

tuple_element()returns the type of an individual element. This function takes an index and the tuple type:

//obtain the type of the first elementT=tuple_element  >::type;//int>

If you need to access the actual element, not its type, use the get()function. Note that tuples use zero-based indexing:

tuple  t;int n=get(t); //get 1st elementget(t)=0.5; //assign 2nd element 

Tuples in the Real World
Let’s examine some of the uses of tuple types. Suppose you need to implement a function that translates a file name into both FILE * and a file descriptor. C++ of course doesn’t allow more than one return type. A common workaround is to define two functions with slightly different names:

int convert_filename(const char * path);FILE * fconvert_filename(const char * path);

The POSIXlibraries are replete with such sets of functions. Overloading won’t do in this case because you can’t define overloaded versions of a function that differ only in their return types:

int convert_filename(const char* path);FILE* convert_filename(const char* path); //error

By using a tuple type to pack the two return types, you can simulate multiple return types for a single function. As always, use a typedefto hide the cumbersome syntax:

typedef tuple file_t;file_t convert_filename(const char* path);

In an object-oriented environment you can extend file_t to accommodate an fstreamobject as well.

A tuple type provides a neat solution to another problemthat I presented here several months ago, namely simulating floating point values with integers. Instead of using two bare integers, you can now use a tuple:

typedef tuple<__int64 int> Currency;

The revised class USD now looks like this:

class USD{private: Currency curr;public: explicit USD(__int64 d=0, int c=0): curr(d,c) {}//..};

As an aside, notice how important it is to declare data members private. Users of this class won’t notice that its implementation has changed because the interface remains intact.

This is very nice, but you’re probably asking: “Can’t I just pack the two integers in a good ol’ struct instead?” Of course you can. However, a tuple offers a bonus: it already overloads the relational operators , ==,etc. Consequently, you can compare two currency values without any effort:

bool operator==(const USD& u1, const USD& u2){ return u1.curr==u2.curr;}

The tuple’s overloaded == returns true if and only if each element in u1 is equal to the corresponding element in u2. For example:

Currency curr1(100,99);  Currency curr2(100,98);Currency curr3(100,98);bool res=curr1==curr2; //falseres=curr2==curr3; //true

The Top of the Poll
Tuples have many other uses. For example, you can create a tuple of references and cv-qualified types:

int i; char c; make_tuple(ref(i),ref(c)); // tuple make_tuple(cref(i), c); // tuple 

The ref class template serves a reference wrapper. Likewise, cref wraps a reference to a const object. To simplify the creation of tuples of reference elements, use the tie()function:

tie(i, c); //same as: make_tuple(ref(i), ref(c));

A tuple containing non-const reference elements can be used to “unpack” another tuple into real objects:

tie(i, c)=make_tuple(1, 'a');

After the assignment, i=1 and c=’a’. This technique may be useful when unpacking a function that returns a tuple.

devx-admin

Share the Post: