Boost logo

Boost :

From: Hamish Mackenzie (boost_at_[hidden])
Date: 2001-11-23 11:17:03


If we are going to introduce new language features how about copying
prolog. I suggested this in a previous post

http://groups.yahoo.com/group/boost/message/14182

Prolog has the same problem as C++ templates and solves it by converting
lists into recursive constructs.

We would add a header file something like

// prologs []
class empty_type_list;

// prologs '.' operator
template< class Head_Item, class Tail >
class dot;

These classes would not need to be defined as they would never be
instantiated.

Then we add a keyword say type_list which could easily be implemented in
a preprocessor for existing compilers. It work like [a,b,c] in prolog

The compiler would treat...

type_list< a, b, c >
as
dot< a, dot< b, dot< c, empty_type_list > > >

Also lets have the [a,b,c|Tail] from prolog too by making these two the
same

type_list< a, b, c | tail >
as
dot< a, dot< b, dot< c, tail > > >

(type_list<> would be the same as empty_type_list)

The rest I think we can do with the existing language features

So your examples would be

> // Declare a class template that can take any number of parameters
> template <typename[] Ts> class Widget;

template< class TypeList > class Widget;

(Yes this does allow other non list classes to be passed but you could
write a class to do the check by specializing for dot and type_list<>)

> // Specializations that kick in
>
> // For one argument only
> template <typename T>
> class Widget
> {
> ...
> };

template< class SingleItem >
class Widget< type_list< SingleItem > >
{
  ...
};
 
> // For more than one argument
> template <typename T, typename[] Ts>
> class Widget : public Widget<T>, public Widget<Ts>
> {
> ...
> };

template< class HeadItem, class Tail >
class Widget< type_list< HeadItem | Tail > >
{
  ...
};

In order to implement the rest of the examples we would need to
implement a tuple class using the type_list.

template< class TypeList >
class tuple;

template< class HeadItem, class Tail >
class tuple< type_list< HeadItem | Tail > > :
    public HeadItem,
    public tuple< Tail >
{
public:
    ...
};

template<>
class tuple< type_list<> >
{
};

Tuples can be constructed using an append operator something like
        tuple<> << 1 << 2.0

We could simplify things by renaming dot => tuple. I can't decide if I
like this idea or not. I don't think it causes any problems but it
makes type_list dependent on tuple (rather than vice versa).
 
> // Declare a safe vararg function
> template <typename[] Ts> void Printf(const char*, Ts);
> // Declare a safe vararg function
> template <typename[] Ts>
> void Printf(const char*, int, Ts);
> // Another one
> template <typename[] Ts>
> void Printf(const char*, double, Ts);

We can't use partial specialisation on template functions.
So instead you will have write a function class...

template< class TypeList >
class Printf_function
{
public:
    void operator() (const char *, tuple< TypeList >);
};

template< class TypeList >
void Printf( const char *s, tuple< TypeList > t )
{
    Printf_function< TypeList > func;
    func( s, t );
}

template< class TypeList >
class Printf_function< type_list< int | TypeList > >
{
public:
    void operator() (const char *,
            tuple< type_list< int | TypeList > > );
};

Ok so that is quite a bit more work but it doesn't interact with
existing function overloading rules. In most cases I think you will be
looking to define a recusive function to enumerate the items in the
tuple and that turns out to be nice and easy...

template< class Item, class Tail >
void print_all( tuple< type_list< Item | Tail > > t )
{
        print( t.head() );
        print_all( t.tail() );
}

void print_all( type_list<> ) {}

> Well if you have the above, you can implement VERY easily and very
> elegantly:
>
> * Typelists (or would they be type vectors?)
> * Tuples
> * Functors
> * Factories
> * Visitors
> * Variants
> * Typesafe variadic utility fns such as
> => printf
> => min/max with multiple args, etc.
> => smart constructors "create a vector containing 1, 2, 3, 4, and 5"
> * many others

I think the prolog like system I have described should allow us to
implement all of the above. More over I think we could easily write a
pre-processor to do the necessary type_list keyword mapping as a proof
of concept.

Hamish


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