Introduction
Generalized functors are important and powerful design artifacts. An excellent introduction on generalized functors idiom, its application and one of the best implementations can be found in [1]. I'll try to retell the primary ideas, concepts and implementation details below with a strong emphasis on the latter as expected from the article title.
So let's discover the generalized functors' goals first. Suppose we have the following C++:
void f2(int, int) {...}
struct A {
void f2(int, int) {...}
};
struct B {
void f2(int, int) {...}
void f2const(int, int) const {...}
};
struct F {
void operator()(int, int) {...}
};
void (*pf2)(int, int) = &f2;
void (A::*paf2)(int, int) = &A::f2;
void (B::*pbf2)(int, int) = &B::f2;
F f;
Collective notion for pf2
(pointer to static
function), paf2
and pbf2
(pointers to member functions), f
(an instance of a class containing corresponding operator()
) is C++ callable entity that means an entity to which functor-call operator ()
can be applied:
pf2(1, 2);
A a;
B* pb = new B;
(a.*paf2)(1, 2);
(pb->*pbf2)(1, 2);
f(1, 2);
What if we want to treat all of them in some generic way, e.g. push them in some "container" and make all the above calls at once via a single method call of such a "container"? The first way to implement this is to develop a special "container" class. Another one is to design a universal adapter class capable of storing and making calls to all the callable entities above. Then these adapter class instances can be stored in the std containers as usual. The latter way is more generic because this adapter class can be used in other applications. It is the class that is called generalized functor. The following pseudocode introduces this:
typedef Functor<
...
template arguments that transfer in some way
the return type and types of all parameters
of operator() - void and int, int for this example
...
> Functor2; // (0)
Functor2 fun1(&f2); // (1)
Functor2 fun2(&a, &A::f2); // (2)
Functor2 fun3(pb, &B::f2); // (2)
Functor2 fun4(f); // (3)
fun1(1, 2); // (4)
fun2(1, 2); // (4)
fun3(1, 2); // (4)
fun4(1, 2); // (4)
// fun1(1); // (5)
// fun2(1, 2, 3); // (5)
// fun3(1, true); // (5)
// bool r = fun4(1, 2); // (5)
Functor2 fun; // (6)
fun = fun1; // (7)
fun = fun2; // (7)
fun = fun3; // (7)
fun = fun4; // (7)
// -------------------------------------------
class FunSet
{
typedef std::vector<Functor2> FV;
FV fv_;
public:
FunSet& operator+=(Functor2 const& f)
{
fv_.push_back(f); // (8)
return *this;
}
void operator()(int i1, int i2) const
{
FV::const_iterator end(fv_.end());
for(FV::const_iterator i = fv_.begin(); i != end; ++i)
(*i)(i1, i2);
}
};
FunSet fs;
fs += fun1;
fs += fun2;
fs += fun3;
fs += fun4;
fs(1, 2);
The above example is simple but has several important issues. First, it shows an application of generalized functors and the power together with the convenience that is achieved. Particularly, the fact that all fun, fun1
-fun4
are of the same type (Functor2
) gives a simple way to solve the above problem of "container" for different callable entities. Second, this example implicitly contains the requirements for a possible generalized functor implementation. We'll frequently refer to them later so let's emphasize:
R1. |
Lines 1-3 imply a universal support for all kinds of callable entities and demand corresponding ctors. |
R2. |
Lines 4 and 5 imply the function call of the underlying callable entity instance to be type safe. This means that if the lines (5) are uncommented, they should not be compilable since they try to do a call either with inappropriate number or types of arguments or with inappropriate return type. |
R3. |
Lines 6-8 imply full support of value semantics, i.e. the need for proper default ctor, operator=, copy ctor and dtor. This is important and very convenient, taking into account C++ forbids assignment and conversions for raw callable entities of different kinds. |
There are additional issues touched at line 0. They concern some other important implementation details:
D1. |
The above listing shows an example of functor for callable entities with the function-call operator () taking two int s as parameters and returning void . Other parameters and return types should be supported of course that leads to a question about the way of parameterization of a generalized functor template. |
D2. |
But what about the different counts of the arguments of the underlying function-call operator () ? Of course, this should be supported, the problem is how to implement this as clear as possible. This is not easy in C++ as it will be shown later. |
Known implementations
The two known implementations of the generalized functors are provided by Loki [2] and boost [3] libraries (the latter is proposed for C++ standard [4]). Providing full generalized functor semantics and functionality, they are completely different in internal implementation, from the concepts to the resulting complexity. Of course, there are other implementations as well. Going through the mentioned R1, R2, R3, D1 and D2 issues, we'll build our own one.
Let's consider D1 issues now. There are two main ways to parameterize the generalized functor template. The first uses function types, and the second uses a pair of return type and typelist containing the types of all the arguments of the corresponding function-call operator ()
:
template <class F> class Functor; (a)
template <class R, class TList> class Functor; (b)
to use them as:
typedef Functor<void (*)(int, int)> Functor2; (a)
typedef Functor<void, TYPELIST_2(int, int)> Functor2; (b)
typedef Functor<void, CreateTL<int, int>::Type> Functor2;
Note: In case (b), TYPELIST
and CreateTL
are a macro [1] and a meta-template respectively, used to generate typelists.
Case (a) (used in boost) looks more elegant, but has several drawbacks. Functions with the same signature can have different modifiers. Cv-qualifiers (const
and volatile
) are the first important examples. They can be applied only to member functions, thus:
typedef Functor<void (*)(int, int) const> Functor2;
declaration will be rejected by the C++ compiler because the corresponding function type is invalid. So the question arises - how to create a generalized functor instance for B::f2const
function in this case? It is possible of course, but at the cost of unnecessary code complication spoiling the initial elegance. Other examples are __cdecl
, __stdcall
, __fastcall
(both for non-member and member functions) and implicit __thiscall
(for member functions) modifiers. Yes, they are all non-standard extensions provided by compiler vendors, but some of the vendors are too important to ignore. The problem is that the function types with different modifiers are of different types, the same can be said about the functors instantiated with them. Summing up, the function type is a too low-level entity to use for parameterization of such a high level entity as generalized functors.
Cases (b) are free from the above disadvantages though they look a bit less elegant. But we can fight for elegance, providing functor creation functions for example. With their help we can bring the client code to the following nice syntax:
FunSet fs;
fs += MakeFunctor(f2);
fs += MakeFunctor(A::f2, &a);
fs += MakeFunctor(B::f2, &b);
To implement MakeFunctor
functions we need mapping between the function type and its return type and the typelist containing types of all its arguments, which can be defined using a common traits idiom:
template <typename F> struct FunTraits;
template <typename R, typename P1, P2>
struct FunTraits<R (*)(P1, P2)>
{
typedef NullType ObjType;
typedef R ResultType;
typedef P1 Parm1;
typedef P2 Parm2;
typedef TYPELIST_2(P1, P2) TypeListType;
};
template <class O, typename R, P1, P2>
struct FunTraits<R (O::*)(P1, P2)>
{
typedef O ObjType;
typedef R ResultType;
typedef P1 Parm1;
typedef P2 Parm2;
typedef TYPELIST_2(P1, P2) TypeListType;
};
The functor creation helper functions are very simple to implement now:
template <typename F> inline
Functor<typename FunTraits<F>::ResultType,
typename FunTraits<F>::TypeListType> MakeFunctor(F fun)
{
return Functor<typename FunTraits<F>::ResultType,
typename FunTraits<F>::TypeListType>(fun);
}
template <typename MF, class P> inline
Functor<typename FunTraits<MF>::ResultType,
typename FunTraits<MF>::TypeListType>
MakeFunctor(MF memfun, P const& pobj)
{
return Functor<typename FunTraits<MF>::ResultType,
typename FunTraits<MF>::TypeListType>(pobj, memfun);
}
Let's move to requirement R1 considerations. You can readily observe that a generalized functor class template is parameterized by the types completely unrelated to the types of the objects that are passed to its ctors. This means that those ctors should be defined as member templates:
template <class R, class TList>
class Functor
{
public:
template <typename F> Functor(F const& fun) { ... }
template <typename P, typename MF> Functor(P const& pobj,
MF memfn)
{ ... }
...
};
Only the ctors know the callable entity type and it gets lost after the ctors exit. But some operations still require the callable entity's type knowledge, e.g. functor copying, assignment and destruction operations. The operator()
should also forward the call to the underlying callable entity instance according to its actual type. So template ctors should store the callable entity type information in some "universal form", which will allow treating them later in some polymorphic way. The most straightforward solution is as follows:
template <class R, class TList>
class Functor
{
struct FunImplBase
{
virtual R call_(...params evaluated from TList...) = 0;
...
};
template <typename F>
class FunctorImpl : public FunImplBase
{
F fun_;
public:
FunctorImpl(F const& fun) : fun_(fun) {}
virtual R call_(...params evaluated from TList...)
{ ... use params to make a call to fun_ ... }
...
};
template <typename P, typename MF>
class MemberFnImpl : public FunImplBase
{
P pobj_;
MF memfun_;
public:
MemberFnImpl(P const& pobj, MF memfun) : pobj_(pobj),
memfun_(fun) {}
virtual R call_(...params evaluated from TList...)
{ ... use params to make a call to memfun_ of pobj_ ... }
...
};
FunImplBase *pimpl_;
public:
template <typename F> Functor(F const& fun)
{
pimpl_ = new FunctorImpl<F>(fun);
}
template <typename P, typename MF> Functor(P const& pobj,
MF memfn)
{
pimpl_ = new MemberFnImpl<P, MF>(pobj, memfn);
}
...
R operator(...params evaluated from TList...)
{
return pimpl_->call_(... params ...);
}
...
};
In the above example, an abstract base class FunImplBase
defines all the operations depending on the different callable entity types. FunctorImpl
and MemberFnImpl
are its concrete successors implementing those operations for non-member functions together with arbitrary functors and member functions respectively. Generalized functor template itself incorporates a pointer to FunImplBase
, initializes it in the corresponding ctors and uses it where it is needed. It should be noted that the above example conceptually resembles Loki's functor template.
Let's address R2 and D2 issues now. Using typelists you can pack an arbitrary number of different types into one type and this is great for many generic algorithms. But this very arbitrary number of types should be fixed in the typelists design (and usually is chosen high enough to fit all uses). A similar problem - C++ has no facility to manipulate function parameter's count and so you can't treat them in a generic way. In our case having some TypeList<T1,T2,T3,...Tn>
type of arbitrary length would be nice to generate the corresponding function e.g. operator()(T1,T2,T3,...Tn)
. This would completely solve the problem of type safe function-call. But as we already said this can't be done in C++ and we have to find out roundabout ways. There are two ways. In the following first way we can declare a Functor
class template and then define partial specializations for all possible count of types in the operator()
:
template <class R, class TList> class Functor;
template <class R> class Functor<R, TYPELIST_0(P1)> { ... };
template <class R, class P1> class Functor<R, TYPELIST_1(P1)>
{ ... };
template <class R, class P1, class P2>
class Functor<R, TYPELIST_2(P1, P2)> { ... };
...
But in this case each specialization also contains all the code independent of the operator()
arguments count. One can try to factor out this code in some way into the base classes for example (as boost does) etc. But the result does not seem to be good.
In the second way we define a single front-end functor template and simply overload all possible operator()
:
template <class R, class TList> class Functor
{
...
operator()()
operator()(T1)
operator()(T1,T2)
...
operator()(T1,T2,...Tn)
...
operator()(T1,T2,T3,...Tmax)
};
This solves the problem but introduces some potential bugs. If we try to use the resulting generalized functor template as in the opening code listings and uncomment the commented line 5, the compiler will gaily compile them guaranteeing runtime crash! The solution is to take FunImplBase
, FunctorImpl
and MemberFnImpl
declarations out of the Functor
template and define specializations for all possible count of types in the call_
functions. See an example for FunImplBase
:
template <class R, class TList> struct FunImplBase;
... partial specializations for different numbers of arguments ...
template <class R, typename P1, P2>
struct FunImplBase<R, TYPELIST_2(P1, P2)>
{
virtual R call_(P1 p1, P2 p2) = 0;
...
};
There are a number of specializations here, but each one contains only one suitable call_
function. So the code for line 5 in the opening code listing is not compilable now. Though the compiler can find a suitable operator()
in the Functor
template, it fails to find a suitable call_
function in a corresponding FunImplBase
specialization. But as you may notice, we've got back to the necessity of partial specializations - not for the Functor
template itself but for some helper classes. This is a bad news. The good and the more important ones are that the specializations contain as little unnecessary code (independent from the count of arguments of the call_
function) as possible. Loki's implementation follows this way and achieves very good code factoring.
We've considered how generalized functor requirements and implementation detail issues (R1, R2, D1 and D2) can be solved and how they are solved in the existing libraries. We'll leave the requirement R3 issues untouched since they do not introduce any new ideas and are rather easy to implement.
Going forward
In the previous section, we discussed the generalized functor requirements, design problems and possible solutions. We've also got to a principle implementation usually used in the existing libraries. In this section, we'll try to investigate and analyze its disadvantages and remove them.
One of the disadvantages which can be discovered from the previous section examples is the need of heap allocation for FunctorImpl
and MemberFnImpl
instances. This is a squander - both from the point of view of speed and memory consumptions (because all general-purpose allocators allocate memory with some granularity wasting some space). Keeping this in mind, Loki provides for its functor template the optimized custom small object allocator. Boost implementation contains a trick that allows to refuse heap allocation for generalized functors for non-member functions, but rolls down to heap allocation with generalized functors in other cases.
How about refusing heap allocation in all cases? The possible solution is to incorporate a buffer of some fixed (but customizable) size into the functor class template itself and use it as a pool for memory allocation. This idea exploits the fact that for all callable entity kinds, only a few bytes of memory are needed to store the internal data. Thus with a functor for a static
function only the function pointer (4 bytes on 32-bit systems) should be stored. With functor to a member function a pointer to the target object instance and a pointer-to-member for a function to be called are needed. The former takes 4 bytes again, while the size of the latter can vary from 4 to 20 bytes (see an excellent study here [5]). Internal data size for an arbitrary functor can't be predicted beforehand, but we know from our experience that functors are usually designed to have only a few data members or no members at all.
This idea can be expressed in the following way:
template <class R, class TList, unsigned int size = 4 * sizeof(void*)>
class Functor
{
...
struct Typeless {
char buffer_[size];
template <class T, class V> T* init(V const& v)
{ new(&buffer[0]) T(v); }
template <typename T> inline T const& get()
const { return *reinterpret_cast<T const*>(&buffer[0]); }
template <typename T> inline T& get()
{ return *reinterpret_cast<T*>(&buffer[0]); }
}
Typeless val_;
FunImplBase<R, TList> *pimpl_;
public:
...
template <typename F> Functor(F const& fun)
{
pimpl_ = val_.init<FunctorImpl<F> >(fun);
}
...
};
Functors designed in the above way, waste some space in the case of least memory-consuming functors for static
functions. But, firstly, when using heap allocation, some memory wastes occur due to the allocation granularity. And, secondly, the profit is admirable - all functor operations involved in copy-by-value support (ctors, dtor, operator=
) work with a giddy speed. These operations are intensively used in important generalized functor applications based on functor chaining and binding.
For the remaining minority of cases when sizeof(T) > size
we should provide in Typeless::init()
switching to normal allocator. The simplest way to do this is the following:
template <class R, class TList,
unsigned int size = 4 * sizeof(void*)>
class Functor
{
...
struct Typeless {
char buffer_[size];
template <class T, class V> T* init(V const& v)
{ new(&buffer[0]) T(v); }
template <typename T> inline T const& get() const
{ return *reinterpret_cast<T const*>(&buffer[0]); }
template <typename T> inline T& get()
{ return *reinterpret_cast<T*>(&buffer[0]); }
}
template <typename T>
struct ByValue
{
template <typename V> inline static T* init(Typeless& val,
V const& v) { return val.template init<T>(v); }
inline static T const& get(Typeless const& val)
{ return val.get<T>(); }
inline static T& get(Typeless& val)
{ return val.get<T>(); }
};
template <typename T>
struct NewAlloc
{
template <typename V> inline static T* init(Typeless& val,
V const& v) { return *val.template init<T*>(new T(v)); }
inline static T const& get(Typeless const& val)
{ return *val.get<T const*>(); }
inline static T& get(Typeless& val)
{ return *val.get<T*>(); }
};
template <typename T>
struct SelectStored
{
typedef typename Select<
sizeof(T)<=sizeof(Typeless),
ByValue<T>,
NewAlloc<T>
>::Result Type;
};
struct Stored
{
template <typename T, typename V> inline T* init(V const& v)
{ return SelectStored<T>::Type::init(val_, v); }
template <typename T> inline T const& get() const
{ return SelectStored<T>::Type::get(val_); }
template <typename T> inline T& get()
{ return SelectStored<T>::Type::get(val_); }
Typeless val_;
};
Stored val_;
FunImplBase *pimpl_;
public:
...
template <typename F> Functor(F const& fun)
{
pimpl_ = val_.init<FunctorImpl<F> >(fun);
}
...
};
In the above code snippet, val_
is used either to store the value of T
entirely, or to store only the pointer to the newly-allocated value. Note: sizeof(T)<=sizeof(Typeless)
expression used in the Select
meta-template is not enough and should be improved by adding alignment calculations (see [6] or [3]).
Digging in we discover one more disadvantage. After introducing val_
, pimpl_
pointer becomes redundant! We always "almost" know that - it is equal to either &val_
or incorporated into val_
itself. So, if we could make such a choice we could throw pimpl_
away. Remember that each instance of a class containing virtual
functions (either own or inherited ones) maintains an invisible pointer to the virtual
methods table which directs the virtual
function calls towards the right function of the right class. If we could deal with it directly and take it out from FunctorImpl
and MemberFnImpl
instances into the Functor
template, we could make all the needed calls to the right FunctorImpl
or MemberFnImpl
functions and additionally save 4 bytes! Of course, we couldn't do it dealing with C++ virtual function mechanism immediately. But we could simulate this mechanism. This is a known and a rather powerful technique (see [6] or [7] for example). For our case it could be applied in the following way:
template <class R, class TList,
unsigned int size = 4 * sizeof(void*)>
class Functor
{
...
struct FunImplBase
{
struct VTable
{
R (*call_)(Functor const&,
...params evaluated from TList...);
...
};
};
template <typename F>
class FunctorImpl : public FunImplBase
{
F fun_;
public:
FunctorImpl(F const& fun) : fun_(fun) {}
static R Call(Functor const& f,
...params evaluated from TList...)
{
FunctorImpl const& this_ =
f.val_.template get<FunctorImpl const>();
... use this_ and params to make a call to fun_ ...
}
...
};
template <class P, class MF>
class MemberFnImpl : public FunImplBase
{
P pobj_;
MF memfun_;
public:
MemberFnImpl(P const& pobj, MF memfun) :
pobj_(pobj), memfun_(fun) {}
static R Call(Functor const& f,
...params evaluated from TList...)
{
MemberFnImpl const& this_ =
f.val_.template get<MemberFnImpl const>();
... use this_ and params to make ...
... a call to memfun_ of pobj_ ...
}
...
};
...
Stored val_;
typename FunImplBase::VTable* vptr_;
public:
...
template <typename F> Functor(F const& fun)
{
FunImplBase* pimpl_ = val_.init<FunctorImpl<F> >(fun);
static typename FunImplBase::VTable vtbl =
{
&FunctorImpl::Call,
...
};
vptr_ = &vtbl;
}
R operator(...params evaluated from TList...)
{
return vptr_->call_(*this,
...params evaluated from TList...);
}
...
};
Note: This is not a plane translation of the previous example with virtual
functions, this is an adapted translation, e.g. pointer to FunImplBase
is thrown away and is replaced by a pointer to a function table, FunctorImpl::Call
function etc. accepts Functor
instance reference as the first argument (not a FunctorImpl
pointer that could be in plane translation). The result seems to be acceptable.
Let's switch to R2 and D2 issues now. We can notice that when calling FunctorImpl::Call
and MemberFnImpl::Call
from operator()
, all its arguments should always be copied. Because, this is a call via a function pointer (as with virtual function call as well by the way) the compiler could not apply any optimizations. So what if we pack operator()
arguments into a tuple and pass it to FunctorImpl::Call
or MemberFnImpl::Call
? Arguments copying overhead will remain the same, but FunctorImpl
and MemberFnImpl
could become independent from operator()
arguments count. It is not shown in the previous listings but in addition to the Call
functions FunctorImplBase
, FunctorImpl
and MemberFnImpl
should also contain functions for value semantics support. So their independence from operator()
arguments count evidently improves the code:
template <class TList> struct CallParms;
... partial specializations for typelists with different length ...
template <typename P1,
typename P2> struct CallParms<TYPELIST_2(P1, P2)>
{
typedef InstantiateH<tTYPELIST_2(P1, P2)> ParmsListType;
static inline ParmsListType Make(P1 p1, P2 p2)
{ ... make ParmsListType tuple from p1 and p2 ... }
};
template <typename CallType, typename R,
class TList> struct FunctorCall;
template <typename CallType, typename R, P1, P2>
struct FunctorCall<CallType, R, TYPELIST_2(P1, P2)>
{
typedef InstantiateH<tTYPELIST_2(P1, P2)> ParmsListType;
template <class Fun> static inline
R Call(Fun const& fun, ParmsListType& parms)
{
return fun(... parameters unpacked from parms ...);
}
template <class PObj> static inline R Call(PObj const& pobj,
CallType memfun, ParmsListType& parms)
{
return (
(*pobj).*memfun)(... parameters unpacked from parms ...);
}
};
...
template <class R, class TList,
unsigned int size = 4 * sizeof(void*)>
class Functor
{
...
typedef typename CallParms<TList>::
ParmsListType ParmsListType;
struct FunImplBase
{
struct VTable
{
R (*call_)(Functor const&, ParmsListType parms);
...
};
};
template <typename F>
class FunctorImpl : public FunImplBase
{
F fun_;
public:
FunctorImpl(F const& fun) : fun_(fun) {}
static R Call(Functor const& f, ParmsListType parms)
{
FunctorImpl const& this_ =
f.val_.template get<FunctorImpl const>();
return FunctorCall<T, R, TList>::Call(this_.fun_,
parms);
}
...
};
template <class P, class MF>
class MemberFnImpl : public FunImplBase
{
P pobj_;
MF memfun_;
public:
MemberFnImpl(P const& pobj, MF memfun) :
pobj_(pobj), memfun_(fun) {}
static R Call(Functor const& f, ParmsListType parms)
{
MemberFnImpl const& this_ =
f.val_.template get<MemberFnImpl const>();
return FunctorCall<T, R, TList>::Call(this_.pobj_,
this_.memfun_, parms);
}
...
};
...
Stored val_;
typename FunImplBase::VTable* vptr_;
public:
...
template <typename F> Functor(F const& fun)
{
FunImplBase* pimpl_ = val_.init<FunctorImpl<F> >(fun);
static typename FunImplBase::VTable vtbl =
{
&FunctorImpl::Call,
...
};
vptr_ = &vtbl;
}
... evaluate Parm1 type from TList ...
... evaluate Parm2 type from TList ...
...
inline R operator()() const
{
return vptr_->call_(*this, CallParms<TList>::Make());
}
inline R operator()(Parm1 p1) const
{
return vptr_->call_(*this, CallParms<TList>::Make(p1));
}
inline R operator()(Parm1 p1, Parm2 p2) const
{
return vptr_->call_(*this,
CallParms<TList>::Make(p1, p2));
}
...
};
Note: In the above listing InstantiateH
- is a kind of GenScatterHierarchy<>
template in Loki used here as a tuple generation engine (see [1] for details).
Packing operator()
arguments into the tuple and passing them in internal calls can lead to additional benefits that exceed the bounds of Functor
implementation itself. E.g. we can add the following overloaded operator()
:
template <class R, class TList,
unsigned int size = 4 * sizeof(void*)>
class Functor
{
... as above ...
inline R operator()(ParmsListType& parms) const
{
return vptr_->call_(*this, parms);
}
};
and use it to pass parms
reference around two or more functors. This can simplify the implementation and even improve the efficiency of functor chaining and binding support. We could even dream of named parameters in the Functor
's operator()
calls - the feature not supported by C++ for simple function-calls.
Conclusions
We've considered generalized functor requirements, existing implementation problems and disadvantages. While trying to solve them we've introduced several ideas, which combined together lead to an implementation that is rather different from the known ones and seems to be more clear and efficient.
Source update (14-Dec-2005)
Generalized functors binding is added. Check out FunBind.h in the source files given with the article.
References
- [1]. Modern C++ Design: Generic Programming and Design Patterns Applied (Addison-Wesley, 2001, ISBN 0201704315), A.Alexandrescu
- [2]. Loki Library Project
- [3]. boost Library Project Home
- [4]. Generalized Function Pointers, H.Sutter
- [5]. Member Function Pointers and the Fastest Possible C++ Delegates, D.Clugston
- [6]. Generic<Programming>: Discriminated Unions (II), A.Alexandrescu
- [7]. Generic<Programming>: Discriminated Unions (III), A.Alexandrescu