Boost logo

Boost :

From: Hamish Mackenzie (boost_at_[hidden])
Date: 2001-11-26 10:17:16


On Mon, 2001-11-26 at 12:29, Peter Dimov wrote:
> Agreed. We already had this discussion on the list before but I'd like to
> revisit it:
>
> class nil;

I think it will be useful to differentiate between an empty type list
and a nil type. For instance, you can append items to an empty list but
appending to a nil type should probably be an error.

How about type_list::nil?

> Have you considered using std::pair as the 'dot pair' type? It doesn't
> really matter which template is used as long as it has two type parameters -
> it doesn't even need a definition. std::pair is handy since it automatically
> maps a value list (a tuple) to a typelist.

It would mean that in order to tell a pair from a tuple you would have
to use a template class that checks for the empty list type at the end
of the list.

So if we are going to do it I would prefer

template< Head, Tail >
class type_list : private boost::compressed_pair< Head, Rest >
{
  typedef compressed_pair< Head, Tail > base;
public:
  typedef typename base::first_type head_type;
  typedef typename base::second_type tail_type;
  typedef typename base::first_param_type head_param_type;
  typedef typename base::second_param_type tail_param_type;
  typedef typename base::first_reference head_reference;
  typedef typename base::second_reference tail_refenece;
  typedef typename base::first_const_reference head_const_refence;
  typedef typename base::second_const_reference tail_const_refence;

  type_list() : base() {}
  type_list(head_param_type x, tail_param_type y) : base(x, y) {}

  head_reference head() { return base::first(); }
  head_const_reference head() const { return base::first(); }

  tail_reference tail() { return base::second(); }
  tail_const_reference tail() const { return base::second(); }

  void swap( type_list & y ) { base::swap( y ); }

  class nil{};
};

This would simplify using tuples and I can't think of a good argument
not to do it. It would however, mean that tuples and type_lists would be
forever linked. Can anyone think of a reason we might want more than
one tuple type?

The alternative would be

template< class TypeList >
class tuple;

template< class Head, class TypeList >
class tuple< type_list< Head, TypeList > >
  : private pair< Head, TypeList >
{
...
};

Adding storage to type_list would not break this approach, so if we
changed our minds later on it would be no big deal (touch wood).

> Why did you reject the make_typelist<...>::type approach?

template< class X >
class foo;

class a;
class b;
class c;

class foo< typename make_typelist< a, b, c >::type >
{
};

typedef foo< typename make_typelist< a, b, c >::type > x;

As I understand it this is not possible with the existing standard and
is unlikely to every work. The compiler would have to try all possible
instaniations of make_typelist to find one that matches.

On another note how about adding

template< class Head >
type_list< Head, type_list::nil > operator << (
  const type_list::nil &t, const Head &h )
{
  return type_list< Head, type_list::nil >( h, t );
}

template< class Head, class H2, class Tail >
type_list< Head, type_list< H2, Tail > > operator << (
  const type_list< H2, Tail > &t, const Head &h )
{
  return type_list< Head, type_list< H2, Tail > >( h, t );
}

template< class Head, class Tail >
Tail operator >> ( const type_list< Head, Tail > &t, Head &h )
{ // Is there a better way to make this exception safe?
  struct assign_if_not_cancelled
  {
    bool cancelled_;
    Head &dest_;
    const Head &source_;
    
    assign_if_not_cancelled( Head &d, const Head &s )
      : cancelled_( false ), dest_( d ), source_( s ) (
    {
    }
    ~assign_if_not_cancelled()
    {
      if( !cancelled_ )
      {
        dest_ = source_;
      }
    }
  } x( h, t.head() );
  
  try
  {
    return t.tail();
  }
  catch( ... )
  {
    x.cancelled_ = true;
    throw;
  }
}

This could be used as follows

template< class TypeList >
void f( TypeList t )
{
  int a;
  double b;
  char *c;
  
  t >> c >> b >> a;
}

...

f( TYPELIST_0 << 1 << 2.0 << "Test" );

Like streams but LIFO rather than FIFO. We could change it to be FIFO if
that makes more sense.

Hamish


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk