21.1 Duos

Ru-Brd

A duo is the assembly of two objects into a single type. This is similar to the std::pair class template in the standard library, but because we will add slightly different functionality to this very basic utility, we opted for a name other than pair to avoid confusion with the standard item. At its very simplest, we can define Duo as follows :

 template <typename T1, typename T2>  struct Duo {      T1 v1;  // value of first field  T2 v2;  // value of second field  }; 

This can, for example, be useful as a return type for a function that may return an invalid result:

 Duo<bool,X> result = foo();  if (result.v1) {  // result is valid; value is in  result.v2   } 

Many other applications are possible.

The benefit of Duo as defined here is not insignificant, but it is rather small. After all, it would not be that much work to define a structure with two fields, and doing so allows us to choose meaningful names for these fields. However, we can extend the basic facility in a few ways to add to the convenience. First, we can add constructors:

 template <typename T1, typename T2>  class Duo {    public:      T1 v1;  // value of first field  T2 v2;  // value of second field   // constructors  Duo() : v1(), v2() {      }      Duo (T1 const& a, T2 const& b)       : v1(a), v2(b) {      }  }; 

Note that we used an initializer list for the default constructor so that the members get zero initialized for built-in types (see Section 5.5 on page 56).

To avoid the need for explicit type parameters, we can further add a function so that the field types can be deduced :

 template <typename T1, typename T2>  inline  Duo<T1,T2> make_duo (T1 const& a, T2 const& b)  {      return Duo<T1,T2>(a,b);  } 

Now the creation and initialization of a Duo becomes more convenient . Instead of

 Duo<bool,int> result;  result.v1 = true;  result.v2 = 42;  return result; 

we can write

 return make_duo(true,42); 

Good C++ compilers can optimize this well enough so that this generates code equivalent to

 return Duo<bool,int>(true,42); 

Another refinement is to provide access to the field types, so that adapter templates can be built on top of Duo :

 template <typename T1, typename T2>  class Duo {    public:      typedef T1 Type1;  // type of first field  typedef T2 Type2;  // type of second field  enum { N = 2 };  // number of fields  T1 v1;  // value of first field  T2 v2;  // value of second field   // constructors  Duo() : v1(), v2() {      }      Duo (T1 const& a, T2 const& b)       : v1(a), v2(b) {      }  }; 

At this stage we're rather close to the implementation of std::pair with the following differences:

  • We use different names.

  • We provide a member N for the number of fields.

  • We have no member template initialization to allow implicit type conversions during construction.

  • We don't provide comparison operators.

A more powerful and cleaner implementation might looks as follows:

  // tuples/duo1.hpp  #ifndef DUO_HPP  #define DUO_HPP  template <typename T1, typename T2>  class Duo {    public:      typedef T1 Type1;  // type of first field  typedef T2 Type2;  // type of second field  enum { N = 2 };  // number of fields  private:      T1 value1;  // value of first field  T2 value2;  // value of second field  public:  // constructors  Duo() : value1(), value2() {      }      Duo (T1 const & a, T2 const & b)       : value1(a), value2(b) {      }  // for implicit type conversion during construction  template <typename U1, typename U2>      Duo (Duo<U1,U2> const & d)       : value1(d.v1()), value2(d.v2()) {      }  // for implicit type conversion during assignments  template <typename U1, typename U2>      Duo<T1, T2>& operator = (Duo<U1,U2> const & d) {          value1 = d.value1;          value2 = d.value2;          return *this;      }  // field access  T1& v1() {          return value1;      }      T1 const& v1() const {          return value1;      }      T2& v2() {          return value2;      }      T2 const& v2() const {          return value2;      }  };  // comparison operators (allow mixed types):  template <typename T1, typename T2,            typename U1, typename U2>  inline  bool operator == (Duo<T1,T2> const& d1, Duo<U1,U2> const& d2)  {      return d1.v1()==d2.v1() && d1.v2()==d2.v2();  }  template <typename T1, typename T2,            typename U1, typename U2>  inline  bool operator != (Duo<T1,T2> const& d1, Duo<U1,U2> const& d2)  {      return !(d1==d2);  }  // convenience function for creation and initialization  template <typename T1, typename T2>  inline  Duo<T1,T2> make_duo (T1 const & a, T2 const & b)  {      return Duo<T1,T2>(a,b);  }  #endif  // DUO_HPP  

We made the following changes:

  • We made the data members private and added access functions.

  • With the explicit initialization of both members in the default constructor

     template <typename T1, typename T2>  class Duo {   Duo() : value1(), value2() {      }   } 

    we made sure that values of built-in types are zero initialized (see Section 5.5 on page 56).

  • We provided member templates so that construction and initialization are possible with mixed types.

  • We provided comparison operators == and != . Note that we introduced separate sets of template parameters for both sides of a comparison to allow for comparisons of mixed types.

All the member templates are used to enable mixed type operations. That is, we can initialize, assign, and compare a Duo for which an implicit type conversion is necessary to perform the task. For example:

  // tuples/duo1.cpp  #include "duo1.hpp"  Duo<float,int> foo ()  {      return make_duo(42,42);  }  int main()  {      if (foo() == make_duo(42,42.0)) {   }  } 

In this program, in foo() there is a conversion from the return type of make_duo() , Duo<int,int> to the return type of foo() , Duo<float,int> . Similarly, the return value of foo() is compared with the return value of make_duo(42, 42.0) , which is a Duo<int,double> .

It would not be difficult to add Trio and other templates to collect larger numbers of values. However, a more structured alternative can be obtained by nesting Duo objects. This idea is developed in the following sections.

Ru-Brd


C++ Templates
C++ Templates: The Complete Guide
ISBN: 0201734842
EAN: 2147483647
Year: 2002
Pages: 185

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