|
Boost : |
From: Andrei Alexandrescu (andrewalex_at_[hidden])
Date: 2001-11-21 11:29:01
> 1. What if the arguments need to be taken in pairs:
>
> template <class T1, class U1, class T2, class U2,....>
> void f(T1, U1, T2, U2,...)
The specialization can reduce 2, 3 or more types at a type from a typelist.
Consider a "type map":
// Declare TypeMap to take an arbitrary number of args
template <typename[] Ts> struct TypeMap;
// Reduction rules
template <typename T, typename U> class TypeMap
{
typedef T Head;
typedef U Tail;
};
template <typename T, typename U, typename[] Ts>
struct TypeMap : TypeMap<T, U>
{
typedef TypeMap<Ts> Tail;
};
The specializations would reduce two types at a time; therefore, there would
be no specialization to handle an instantiation such as TypeMap<int, char,
short int> so that would be a compile time error.
> 2. What about the "combinatoric explosion of cv-qualifiers" problem:
>
> void f(T1&, T2&);
> void f(T1&, T2 const&);
> void f(T1&, T2 volatile&);
> void f(T1&, T2 const volatile&);
> void f(T1 const&, T2&);
> void f(T1 const&, T2 const&);
> void f(T1 const&, T2 volatile&);...
>
> It's 4^n problem :-(
This is mitigated by the ability of various fns to be templates themselves;
that way, you don't really have to specify cv-qualifiers unless you want to
differentiate among them. Consider:
// Declare Fun to take an arbitrary number of args
template <typename[] Ts> void Fun(Ts);
// Fun's implementations
template <typename T, typename[] Ts>
void Fun(T&, Ts)
{
... will handle cv-qualified types as well ...
}
Now I realize a couple of more problems:
3. Handling empty typelists is problematic. For example, in the Printf
example in my previos post, you need two overloads for handling, say, int:
template<typename[] Ts>
void Printf(const char* s, int x, Ts tail)
{
...
}
void Printf(const char* s, int x)
{
...
}
The first could use the second, but if Ts would be allowed to be empty,
you'd only have to write one version.
4. The entities dubbed as typename[] are new entities. They are not types,
nor templates. They are sort of placeholders for lists of types. This is not
quite clean.
5. Implementing variadic functors still is problematic. Consider
implementing a variadic functor that wants to forward to a pointer to
function:
template <typename[] Ts> class Functor
{
...
};
void Fun(int, double);
...
Functor<int, double> myFunctor(&Fun);
myFunctor(4, 5.5);
Now, there are two problems: (1) what type do you use inside Functor for
storing the pointer to function, and (2) how do you implement
Functor<Ts>::operator()? For (1), you need to specify "a pointer to function
taking the same arguments as Ts specifies". In this case the typedef would
look like:
template <typename[] Ts> class Functor
{
typedef void (*TpFun)(Ts);
TpFun pFun_;
public:
Functor(TpFun pFun) : pFun_(pFun) {}
...
};
That's not bad, but illustrates just how troublesome is to define a solid
facility for variable lists of type/values. I'd be glad if anyone would come
with ideas.
Andrei
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk