Variadic tuple<..> — clever vs obvious

I mentioned in my previous post how the tuple<..> template class will be defined with variadic template parameters in the future.

template< typename ... TYPEs > class tuple;

How do you define the body of a template like that? The implementation described in N2080 (see section A.1 on page 10) essentially defines tuple as a recursive series of base classes, where tuple<A,B,C> inherits from tuple<B,C> which in turn inherits from tuple<C>. In this implementation, tuple<A,B,C> only has to provide a member for type A, while tuple<B,C> provides the member for B and tuple<C> provides the member for type C.

  // Based on implementation in N2080
  template< typename ... TYPEs >
  class
tuple;

  // Specialization for empty tuple
  template< >
  class
tuple< >
  { };

  // Specialization for non-empty tuples
  template< typename Head, typename ... Tail >
  class
tuple< Head, Tail ... >
  : private tuple< Tail ... >
  { protected:
      Head m_head;

    /* .. etc .. */
  };

This is truly a beautiful solution, elegant and clever. It’s too bad the types end up in reverse order, which will matter in C++0x when tuple becomes a POD type. The restrictions on POD are loosening in C++0x, partly to make them work with tuple.

The above implementation would mean you’d have to reverse the values in an initialization list.

// Reverse the values in the initialization list.
tuple< double, char > my_tuple = { 'A', 3.2345 };

Probably the nicest way to solve the reverse problem is to make Head variadic instead of Tail.

/* .. as above .. */

  // Specialization for non-empty tuples
  template< typename ... Head, typename Tail >
  class
tuple< Head ..., Tail >
  : private tuple< Head ... >
  { protected:
      Tail m_tail;

    /* .. etc .. */
  };

I’m pretty sure that will work — I’ll check it when I get a compliant C++ compiler. This solution should be obvious, but people like me are used to thinking of a list as a single-link chain of cons cells, where car is Head and cdr is Tail. The pattern matching in Erlang also encourages <Head,Tail…> thinking instead of <Head…,Tail>.

The current Boost (1_37) implementation solves this problem by making the tail a member variable instead of a supertype. It’s a little more complicated than that — Boost cannot use variadic template params of course. And Boost uses the boost::tuples::details::cons struct to implement the recursive typelist. But it boils down to a head member var followed by tail.

Another possibility is to work from a reversed typelist.

# include <boost/mpl/assert.hpp>
# include <boost/mpl/list.hpp>
# include <boost/mpl/reverse.hpp>
# include <boost/mpl/front.hpp>
# include <boost/mpl/pop_front.hpp>
# include <boost/type_traits/is_same.hpp>

namespace mpl = boost::mpl;
using boost::is_same;

  typedef
  mpl::list< int, float, double >::type
typelist;

  typedef
  mpl::reverse< typelist >::type
reversed_typelist;

  typedef
  mpl::front< reversed_typelist >::type
head_reversed;

  typedef
  mpl::pop_front< reversed_typelist >::type
tail_reversed;

  typedef
  mpl::front< tail_reversed >::type
second_reversed;

BOOST_MPL_ASSERT( (is_same< head_reversed, double >));
BOOST_MPL_ASSERT( (is_same< second_reversed, float >));

But at this point I have to confess that as much as I love clever recursive solutions, what I really want is a dumb iterating solution. After all, the operator is an iterator of sorts. It expands a packed term into a sequence of resolved terms. I was naively hoping that something like this would work.

/* This is probably illegal */

  template< typename ... TYPEs >
  class
tuple
  {
    protected:
      TYPEs ... values;

    /* .. etc .. */
  };

I just feel this is clearly expressed, even if it’s not flashingly brilliant.

But I’m pretty sure only generates comma-separated lists. So it can be used in template and function parameter lists, and to generate a comma-separated list of expressions. But it won’t work in the situation above. Don’t quote me on this however — I haven’t messed with gcc4.3 in experimental C++0x mode yet.

Comments

Leave a Reply