|
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