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