Usage


Tuples live in namespace tuples, which in turn is inside namespace boost. Include "boost/tuple/tuple.hpp" to use the library. The relational operators are defined in the header "boost/tuple/tuple_comparison.hpp". Input and output of tuples are defined in "boost/tuple/tuple_io.hpp". A few of the key tuple components (tie and make_tuple) are also available directly in namespace boost. In this section, we'll cover how tuples are used in some typical scenarios, and how it is possible to extend the functionality of the library to best fit our purposes. We'll start with the construction of tuples, and gradually move on to topics that include the details of how tuples can be utilized.

Constructing Tuples

The construction of a tuple involves declaring the types and, optionally, providing a list of initial values of compatible types.[1]

[1] The constructor arguments do not have to be of the exact type specified for the elements when specializing the tuple so long as they are implicitly convertible to those types.

 boost::tuple<int,double,std::string>    triple(42,3.14,"My first tuple!"); 

The template parameters to the class template tuple specify the element types. The preceding example shows the creation of a tuple with three types: an int, a double, and a std::string. Providing three parameters to the constructor initializes the values of all three elements. It's also possible to pass fewer arguments than there are elements, which results in the remaining elements being default initialized.

 boost::tuple<short,int,long> another; 

In this example, another has elements of types short, int, and long, and they are all initialized to 0.[2] Regardless of the set of types for your tuples, this is how they are defined and constructed. So, if one of your tuple's element types is not default constructible, you need to initialize it yourself. Compared to defining structs, tuples are much simpler to declare, define, and use. There's also the convenience function, make_tuple, which makes creating tuples easier still. It deduces the types, relieving you from the monotony (and chance of error!) of specifying them explicitly.

[2] Within the context of a template, T() for a built-in type means initialization with zero.

 boost::tuples::tuple<int,double> get_values() {   return boost::make_tuple(6,12.0); } 

The function make_tuple is analogous to std::make_pair. By default, make_tuple sets the types of the elements to non-const, non-referencethat is, the plain, underlying types of the arguments. For example, consider the following variables:

 int plain=42; int& ref=plain; const int& cref=ref; 

These three variables are named after their cv-qualification (constness) and whether they are references. The tuples created by the following invocations of make_tuple all have one int element.

 boost::make_tuple(plain); boost::make_tuple(ref); boost::make_tuple(cref); 

This isn't always the right behavior, but on most occasions it is, which is the reason why it's the default. To make an element of a tuple to be of reference type, use the function boost::ref, which is part of another Boost library called Boost.Ref. The following three lines use the variables that we declared earlier, but this time the tuples have an int& element, except for the last, which has a const int& element (we can't remove the constness of cref):

 boost::make_tuple(boost::ref(plain)); boost::make_tuple(boost::ref(ref)); boost::make_tuple(boost::ref(cref)); 

If the elements should be const references, use boost::cref from Boost.Ref. Here, the three tuples have one const int& element:

 boost::make_tuple(boost::cref(plain)); boost::make_tuple(boost::cref(ref)); boost::make_tuple(boost::cref(cref)); 

It's probably obvious, but ref and cref have plenty of uses in other contexts too. In fact, they were created as a part of the Boost.Tuple library, but were later moved to a separate library because of their general utility.

Accessing tuple Elements

The elements of a tuple are accessed either through the tuple member function get or the free function get. They both require a constant integral expression designating the index of the element to retrieve.

 #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" int main() {   boost::tuple<int,double,std::string>    triple(42,3.14,"The amazing tuple!");    int i=boost::tuples::get<0>(triple);   double d=triple.get<1>();   std::string s=boost::get<2>(triple); } 

In the example, a tuple with three elements with the innovative name triple was created. triple contained an int, a double, and a string, which were retrieved through the get functions.

 int i=boost::tuples::get<0>(triple); 

Here, you see the free function get at work. It takes a tuple as its one argument. Note that supplying an invalid index causes an error at compilation time. The precondition is that the index be a valid index for the tuple type.

 double d=triple.get<1>(); 

This code shows using the member function get. The preceding line could also have been written like this:

 double& d=triple.get<1>(); 

The preceding binding to a reference works because get always returns a reference to the element. If the tuple, or the type, is const, a const reference is returned. The two functions are equivalent, but on some compilers only the free function works correctly. The free function has the advantage of providing a consistent extraction style for types other than tuple. One advantage of accessing the elements of tuples by index rather than by name is that it enables generic solutions, because there are no dependencies on a certain name, but only to an index. More on this later.

Tuple Assignment and Copy Construction

tuples can be assigned and copy constructed, providing that there are suitable conversions between the types of the elements in the two tuples. To assign or copy tuples, member-wise assignment or copying is performed, so the two tuples must have the same number of elements. The elements in the source tuple must be convertible to those of the destination tuple. The following example shows how this works.

 #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" class base { public:   virtual ~base() {};   virtual void test() {     std::cout << "base::test()\n";   } }; class derived : public base { public:   virtual void test() {     std::cout << "derived::test()\n";   } }; int main() {   boost::tuple<int,std::string,derived> tup1(-5,"Tuples");   boost::tuple<unsigned int,std::string,base> tup2;   tup2=tup1;   tup2.get<2>().test();   std::cout << "Interesting value: "              << tup2.get<0>() << '\n';   const boost::tuple<double,std::string,base> tup3(tup2);   tup3.get<0>()=3.14; } 

The example begins by defining two classes, base and derived, which are used as elements of two tuple types. The first tuple contains three elements of types, int, std::string, and derived. The second tuple consists of three elements of the compatible types unsigned int, std::string, and base. Consequently, the two tuples meet the requirements for assignment, which is why tup2=tup1 is valid. In that assignment, the third element of tup1, which is of type derived, is assigned to the third element of tup2, which is of type base. The assignment succeeds, but the derived object is sliced, so this defeats polymorphism.

 tup2.get<2>().test(); 

That line extracts a base&, but the object in tup2 is of type base, so it winds up calling base::test. We could have made the behavior truly polymorphic by changing the tuples to contain references or pointers to base and derived, respectively. Note that numeric conversion dangers (loss of precision, positive and negative overflow) apply when converting between tuples as well. These dangerous conversions can be made safe with the help of the Boost.Conversion library, covered in "Library 2: Conversion."

The next line in the example copy-constructs a new tuple, tup3, with different, but still compatible types, from tup2.

 const boost::tuple<double,std::string,base> tup3(tup2); 

Note that tup3 is declared const. This implies that there is an error in the example. See if you can you spot it. I'll wait…. Did you see it? Here it is:

 tup3.get<0>()=3.14; 

Because tup3 is const, get returns a const double&. This means that the assignment statement is ill-formed, and the example doesn't compile. Assignment and copy construction between tuples are intuitive, because the semantics are exactly the same for the tuples as for the individual elements. By way of example, let's see how to give polymorphic behavior to the derived-to-base assignment between tuples.

 derived d; boost::tuple<int,std::string,derived*>    tup4(-5,"Tuples",&d); boost::tuple<unsigned int,std::string,base*> tup5; tup5=tup4; tup5.get<2>()->test(); boost::tuple<int,std::string,derived&>   tup6(12,"Example",d);   boost::tuple<unsigned int,std::string,base&> tup7(tup6); tup7.get<2>()->test(); 

In both cases, derived::test is called, which is exactly what we want. tup6 and tup7 are not assignable because you can't assign to a reference, which is why tup7 is copy constructed from tup6 and tup6 is initialized with d. Because tup4 and tup5 use pointers for their third element, they do support assignment. Note that typically smart pointers are best in tuples (as opposed to raw pointers), because they alleviate the need to manage the lifetime of the resources to which the pointers refer. However, as tup4 and tup5 show, pointers don't always refer to something requiring memory management in the tuples. (Refer to "Library 1: Smart_ptr 1" for the details on the powerful smart pointers in Boost.)

Comparing Tuples

To compare tuples, you must include "boost/tuple/tuple_comparison.hpp". The relational tuple operators are ==,!=,<,>,<= and >=, and they invoke the same operator for each element pair, in order, in the tuples being compared. These pair-wise comparisons short circuit, meaning that they only compare as many pairs as needed to arrive at the correct result. Only tuples with the same number of elements can be compared and, as should be obvious, the corresponding element types in the two tuples must be comparable. The test for equality returns TRue if all of the element pairs of the two tuples are also equal. If any one equality comparison between element pairs returns false, so does operator==. The inequality test is analogous, but returns the inverse result. The rest of the relational operators perform lexicographical comparisons.

Here's a sample program showing the comparison operators in action.

 #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" #include "boost/tuple/tuple_comparison.hpp" int main() {   boost::tuple<int,std::string> tup1(11,"Match?");   boost::tuple<short,std::string> tup2(12,"Match?");   std::cout << std::boolalpha;   std::cout << "Comparison: tup1 is less than tup2\n";   std::cout << "tup1==tup2: " << (tup1==tup2) << '\n';    std::cout << "tup1!=tup2: " << (tup1!=tup2) << '\n';   std::cout << "tup1<tup2:  " << (tup1<tup2) << '\n';   std::cout << "tup1>tup2:  " << (tup1>tup2) << '\n';   std::cout << "tup1<=tup2: " << (tup1<=tup2) << '\n';   std::cout << "tup1>=tup2: " << (tup1>=tup2) << '\n';   tup2.get<0>()=boost::get<0>(tup1); //tup2=tup1 also works   std::cout << "\nComparison: tup1 equals tup2\n";     std::cout << "tup1==tup2: " << (tup1==tup2) << '\n';    std::cout << "tup1!=tup2: " << (tup1!=tup2) << '\n';   std::cout << "tup1<tup2:  " << (tup1<tup2) << '\n';   std::cout << "tup1>tup2:  " << (tup1>tup2) << '\n';   std::cout << "tup1<=tup2: " << (tup1<=tup2) << '\n';   std::cout << "tup1>=tup2: " << (tup1>=tup2) << '\n'; } 

As you can see, the two tuples, tup1 and tup2, don't have exactly the same type, but the types are still comparable. For the first set of comparisons, the tuples have different values for the first element, but for the second set, the tuples are equal. This is the output from running the program.

 Comparison: tup1 is less than tup2 tup1==tup2: false tup1!=tup2: true tup1<tup2:  true tup1>tup2:  false tup1<=tup2: true tup1>=tup2: false Comparison: tup1 equals tup2 tup1==tup2: true tup1!=tup2: false tup1<tup2:  false tup1>tup2:  false tup1<=tup2: true tup1>=tup2: true 

One important aspect of the support for comparisons is that tuples can be sorted, which means they can be stored in associative containers. It is sometimes desirable to sort based on one of the elements of a tuple (creating a strict weak ordering), which we can accomplish with a simple, generic solution.

 template <int Index> class element_less { public:   template <typename Tuple>    bool operator()(const Tuple& lhs,const Tuple& rhs) const {     return boost::get<Index>(lhs)<boost::get<Index>(rhs);    }  }; 

This shows one of the advantages of accessing elements by index rather than by name; it is very easy to create generic constructs that perform powerful operations. The sorting performed by our element_less can be used like this:

 #include <iostream> #include <vector>   #include "boost/tuple/tuple.hpp" #include "boost/tuple/tuple_comparison.hpp" template <int Index> class element_less { public:   template <typename Tuple>    bool operator()(const Tuple& lhs,const Tuple& rhs) const {     return boost::get<Index>(lhs)<boost::get<Index>(rhs);    }  }; int main() {   typedef boost::tuple<short,int,long,float,double,long double>      num_tuple;   std::vector<num_tuple> vec;   vec.push_back(num_tuple(6,2));   vec.push_back(num_tuple(7,1));   vec.push_back(num_tuple(5));   std::sort(vec.begin(),vec.end(),element_less<1>());   std::cout << "After sorting: " <<      vec[0].get<0>() << '\n' <<     vec[1].get<0>() << '\n' <<     vec[2].get<0>() << '\n'; } 

vec is populated with three elements. The sorting is performed on the second element of the tuples using the element_less<1> function object from the template that we created earlier. There are more applications for this kind of function object, such as when searching for certain tuple elements.

Tying Tuple Elements to Variables

A handy feature of the Boost.Tuple library is "tying" tuples to variables. Tiers are tuples created by the overloaded function template boost::tie, such that all of the elements are non-const reference types. As a result, ties must be initialized with lvalues, and thus tie's arguments are non-const reference types, too. Because the resulting tuples have non-const reference elements, any assignment to the elements of such a tuple are assignments through non-const references to the lvalues with which tie was called. This ties existing variables to a tuple, hence the name!

The following example first shows the obvious way of getting values out of a returned tuple. Then, it shows the same operation using a tied tuple to assign values directly to variables. To make the example more interesting, we'll begin by defining a function that returns the greatest common divisor and the least common multiple of two values. The values are, of course, grouped together as a tuple return type. You'll notice that the functions for calculating the greatest common divisor and least common multiple come from another Boost libraryBoost.Math.

 #include <iostream> #include "boost/tuple/tuple.hpp" #include "boost/math/common_factor.hpp" boost::tuple<int,int> gcd_lcm(int val1,int val2) {   return boost::make_tuple(     boost::math::gcd(val1,val2),     boost::math::lcm(val1,val2)); } int main() {   //The "old" way   boost::tuple<int,int> tup;   tup=gcd_lcm(12,18);   int gcd=tup.get<0>());   int lcm=tup.get<1>());   std::cout << "Greatest common divisor: " << gcd << '\n';   std::cout << "Least common multiple:   " << lcm << '\n';   //The "new" way   boost::tie(gcd,lcm)=gcd_lcm(15,20);   std::cout << "Greatest common divisor: " << gcd << '\n';   std::cout << "Least common multiple:   " << lcm << '\n'; } 

In some cases, we may not be interested in all of the elements of the returned tuple, and this too is supported by tie. There is a special objectboost:: tuples::ignorethat discards a tuple element's value. If in the preceding example we were only interested in the greatest common divisor, we could have expressed it as follows:

 boost::tie(gcd,boost::tuples::ignore)=gcd_lcm(15,20); 

The alternative is to create a variable, pass it to tie, and then ignore it in the rest of the current scope. That leaves maintainers to question the variable's existence. Using ignore clearly proclaims that the code doesn't use that value from the tuple.

Note that tie also supports std::pair. The usage is just like tying values from boost::tuples.

 std::pair<short,double> p(3,0.141592); short s; double d; boost::tie(s,d)=p; 

Tying tuples is more than a mere convenience; it helps make the code clearer.

Streaming Tuples

Each of the examples in this chapter extracted the elements of tuples just to be able to stream them to std::cout. This works, but there's actually an easier way. The tuple library supports both input and output streaming; operator>> and operator<< are overloaded for tuples. There are also manipulators to change the default delimiters used for input and output streaming. Changing the delimiters for input changes what operator>> looks for to recognize element values. Let's examine these things in a simple program that reads and writes tuples. Note that to use tuple streaming, you need to include the header "boost/tuple/tuple_io.hpp".

 #include <iostream> #include "boost/tuple/tuple.hpp" #include "boost/tuple/tuple_io.hpp" int main() {   boost::tuple<int,double> tup1;   boost::tuple<long,long,long> tup2;   std::cout << "Enter an int and a double as (1 2.3):\n";   std::cin >> tup1;   std::cout << "Enter three ints as |1.2.3|:\n";   std::cin >> boost::tuples::set_open('|') >>     boost::tuples::set_close('|') >>     boost::tuples::set_delimiter('.') >> tup2;   std::cout << "Here they are:\n"            << tup1 << '\n'            << boost::tuples::set_open('\"') <<     boost::tuples::set_close('\"') <<     boost::tuples::set_delimiter('-');   std::cout << tup2 << '\n'; } 

The previous example shows how to use the streaming operators together with tuples. The default delimiters for tuples are ( (left parenthesis) as opening delimiter, ) (right parenthesis) for the closing delimiter, and a space for delimiting tuple element values. This implies that to get our program working correctly, we need to give the program input like(12 54.1) and |4.5.3|. Here's a sample run.

 Enter an int and a double as (1 2.3): (12 54.1) Enter three ints as |1.2.3|: |4.5.3| Here they are: (12 54.1) "4-5-3" 

The support for streaming is convenient and, with the support of the delimiter manipulators, it's easy to make streaming compatible even with legacy code that has been updated to use tuples.

Finding Out More About Tuples

There are more facilities for tuples than those we've already seen. These more advanced features are vital for creating generic constructs that work with tuples. For example, you can get the length of a tuple (the number of elements), retrieve the type of an element, and use the null_type tuple sentinel to terminate recursive template instantiations.

It's not possible to iterate over the elements of a tuple with a for loop, because get requires a constant integral expression. However, using a template metaprogram, we can print all the elements of a tuple.

 #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" template <typename Tuple,int Index> struct print_helper {   static void print(const Tuple& t) {     std::cout << boost::tuples::get<Index>(t) << '\n';     print_helper<Tuple,Index-1>::print(t);   } }; template<typename Tuple> struct print_helper<Tuple,0> {   static void print(const Tuple& t) {     std::cout << boost::tuples::get<0>(t) << '\n';   } }; template <typename Tuple> void print_all(const Tuple& t) {   print_helper<     Tuple,boost::tuples::length<Tuple>::value-1>::print(t); } int main() {   boost::tuple<int,std::string,double>      tup(42,"A four and a two",42.424242);   print_all(tup); } 

In the example, a helper class template, print_helper, is a metaprogram that visits all indices of a tuple, printing the element for each index. The partial specialization terminates the template recursion. The function print_all supplies the length of its tuple parameter, plus the tuple to a print_helper constructor. The length of the tuple is retrieved like this:

 boost::tuples::length<Tuple>::value 

This is a constant integral expression, which means it can be passed as the second template argument for print_helper. However, there's a caveat to our solution, which becomes clear when we see the output from running the program.

 42.4242 A four and a two 42 

We're printing the elements in reverse order! Although this could be considered a feature in some situations (he says slyly), it's certainly not the intention here. The problem is that print_helper prints the value of the boost::tuples::length<Tuple>::value-1 element first, then the value of the previous element, and so on, until the specialization prints the first element's value. Rather than using the first element as the special case and starting with the last element, we need to start with the first element and use the last element as the special case. How is that possible? The solution becomes apparent after you know that tuples are terminated with a special type, boost::tuples:: null_type. We can always be certain that the last type in a tuple is null_type, which also means that our solution involves a specialization or function overload for null_type.

The remaining issue is getting the first element's value followed by the next, and so on, and then stopping at the end of the list. tuples provide the member functions get_head and get_tail to access the elements in them. As its name suggests, get_head returns the head of the sequence of valuesthat is, the first element's value. get_tail returns a tuple with all but the first value in the tuple. That leads to the following solution for print_all.

 void print_all(const boost::tuples::null_type&) {} template <typename Tuple> void print_all(const Tuple& t) {   std::cout << t.get_head() << '\n';   print_all(t.get_tail()); } 

This solution is shorter than the original, and it prints the element values in the correct order. Each time the function template print_all executes, it prints one element from the beginning of the tuple and then recurses with a tuple of all but the first value in t. When there are no more values in the tuple, the tail is of type null_type, the overloaded function print_all is called, and the recursion terminates.

It can be useful to know the type of a particular element such as when declaring variables in generic code that are initialized from tuple elements. Consider a function that returns the sum of the first two elements of a tuple, with the additional requirement that the return type must correspond to the largest type (for example, with regards to range of integral types) of the two. Without somehow knowing the types of the elements, it would be impossible to create a general solution to this. This is what the helper template element<N,Tuple>::type does, as the following example shows. The problem we're facing not only involves calculating which element has the largest type, but declaring that type as the return value of a function. This is somewhat complicated, but we can solve it using an extra level of indirection. This indirection comes in the form of an additional helper template with one responsibility: to provide a typedef that defines the larger of two types. The code may seem a little hairy, but it does the job.

 #include <iostream> #include "boost/tuple/tuple.hpp" #include <cassert> template <bool B,typename Tuple> struct largest_type_helper {   typedef typename boost::tuples::element<1,Tuple>::type type; }; template<typename Tuple> struct largest_type_helper<true,Tuple> {   typedef typename boost::tuples::element<0,Tuple>::type type; }; template<typename Tuple> struct largest_type {   typedef typename largest_type_helper<     (sizeof(boost::tuples::element<0,Tuple>)>      sizeof(boost::tuples::element<1,Tuple>)),Tuple>::type type;   }; template <typename Tuple>    typename largest_type<Tuple>::type sum(const Tuple& t) {     typename largest_type<Tuple>::type       result=boost::tuples::get<0>(t)+       boost::tuples::get<1>(t);   return result; } int main() {   typedef boost::tuple<short,int,long> my_tuple;   boost::tuples::element<0,my_tuple>::type first=14;   assert(type_id(first) == typeid(short));   boost::tuples::element<1,my_tuple>::type second=27;   assert(type_id(second) == typeid(int));   boost::tuples::element<     boost::tuples::length<my_tuple>::value-1,my_tuple>::type        last;   my_tuple t(first,second,last);   std::cout << "Type is int? " <<      (typeid(int)==typeid(largest_type<my_tuple>::type)) << '\n';   int s=sum(t); } 

If you didn't quite follow the exercise in template metaprogramming, don't worryit's absolutely not a requirement for utilizing the Tuple library. Although this type of coding takes some time getting used to, the idea is really quite simple. largest_type gets the typedef from one of the two helper class templates, largest_type_helper, where one version is partially specialized on the Boolean parameter. This parameter is determined by comparing the size of the two first elements of the tuple (the second template parameter). The result of this is a typedef that represents the larger of the two types. Our function sum uses that type as the return value, and the rest is simply a matter of adding the two elements.

The rest of the example shows how to use the function sum, and also how to declare variables with types from certain tuple elements. The first two use a hardcoded index into the tuple.

 boost::tuples::element<0,my_tuple>::type first=14; boost::tuples::element<1,my_tuple>::type second=27; 

The last declaration retrieves the index of the last element of the tuple, and uses that as input to the element helper to (generically) declare the type.

 boost::tuples::element< boost::tuples::length<my_tuple>::value-1,my_tuple>::type last; 

Tuples and for_each

The method that we used to create the print_all function can be extended to create a more general mechanism like std::for_each. For example, what if we didn't want to print the elements, but rather wanted to sum them or copy them, or what if we wanted to print only some of them? Sequential access to the tuple elements isn't straightforward, as we discovered when we developed the preceding examples. It makes sense to create a general solution that accepts a function or function object argument to invoke on the tuple elements. This enables not only the (rather limited) print_all function's behavior, but also that of any function that can accept the types of elements from a tuple. The following example creates a function template called for_each_element to do just that. For the sake of argument, the example shows two function objects to show the workings of for_each_element.

 #include <iostream> #include <string> #include <functional> #include "boost/tuple/tuple.hpp" template <typename Function> void for_each_element(   const boost::tuples::null_type&, Function) {} template <typename Tuple, typename Function> void        for_each_element(Tuple& t, Function func) {     func(t.get_head());     for_each_element(t.get_tail(),func); } struct print {   template <typename T> void operator()(const T& t) {     std::cout << t << '\n';   } }; template <typename T> struct print_type {   void operator()(const T& t) {     std::cout << t << '\n';   }   template <typename U> void operator()(const U& u) {} }; int main() {   typedef boost::tuple<short,int,long> my_tuple;   boost::tuple<int,short,double> nums(1,2,3.01);   for_each_element(nums, print());   for_each_element(nums, print_type<double>()); } 

The function for_each_element reuses the strategy from earlier examples, by overloading the function with a version that accepts an argument of type null_type that signals the end of the tuple's elements, to do nothing. Let's look at the function where the work is done.

 template <typename Tuple, typename Function> void        for_each_element(Tuple& t, Function func) {     func(t.get_head());     for_each_element(t.get_tail(),func); } 

The second template and function parameter specifies the function (or function object) to call with the tuple elements as argument. for_each_element first invokes the function (object) with the element returned from get_head. One way to think of it is that get_head returns the current element of the tuple. Then, it recursively calls itself with the tail or remaining elements of the tuple. The next call extracts the head element and calls the function (object) with it and recurses again, and so on. Eventually, get_tail finds no more elements and returns an instance of null_type, which ends the recursion by matching the non-recursive for_each_element overload. That's all there is to for_each_element!

Next, the example illustrates two function objects that contain nice techniques for reuse in other contexts. One is the print function object.

 struct print {   template <typename T> void operator()(const T& t) {     std::cout << t << '\n';   } }; 

There is nothing fancy about this print function object, but as it turns out, many programmers are unaware of the fact that the function call operator can be templated! Typically, function objects are parameterized on one or more types that they should work with, but that doesn't work for tuples because the elements are typically of different types. Thus, the parameterization is not on the function object itself, but on the function call operator, with the added benefit that using it is much simpler, as shown here.

 for_each_element(nums, print()); 

There's no need to specify the type, which would have been required with a parameterized function object. Pushing the template parameters onto the member functions of a class is sometimes useful and often user-friendly.

The second function object prints all elements of a certain type. This kind of filtering can be used to extract elements of compatible types, too.

 template <typename T> struct print_type {   void operator()(const T& t) {     std::cout << t << '\n';   }   template <typename U> void operator()(const U& u) {} }; 

This function object displays another useful technique, which I refer to as the discarding overload. It's used to ignore the elements passed to it except those of type T untouched. The trick involves an overload with a better match for all but a certain type. That bell you hear ringing is probably from the close connection this technique has with the sizeof trick and the ellipsis (...) construct, which is used to make decisions at compile time, but that doesn't work here, where the function is actually called but doesn't do anything. The function object is used like this:

 for_each_element(print_type<double>(),nums); 

Easy to use, easy to write, and it adds value. That's probably not as much a property of the function object as it is of the Tuple library that enables the use of these and other idioms.



    Beyond the C++ Standard Library(c) An Introduction to Boost
    Beyond the C++ Standard Library: An Introduction to Boost
    ISBN: 0321133544
    EAN: 2147483647
    Year: 2006
    Pages: 125

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net