Hugo Arregui, Carlos Castro and Daniel Gutson work out how to combine two useful techniques.
Aspect Oriented Programming (AOP) is a programming paradigm that makes possible to clearly express programs separated into ‘aspects’, including appropriate isolation, composition and reuse of the aspect code [ Kiczales97 ]. AOP defines weaving as the process of composing the aspects into a single entity.
Independently, there are situations in which a base class needs to know its subclass, e.g. for type-safe downcasts. The Curiously Recurring Template Pattern (CRTP) is a C++ idiom in which a class X derives from a class template instantiation using X itself as template argument [ Abrahams04 ]. This way, the base class can know the derived type.
Both AOP and the CRTP are widely adopted C++ programming techniques. In particular, there exists an AOP easy implementation using templates [ Spinczyk05 ]. However, a C++ grammar incompatibility arises when combining AOP and CRTP. While there exists a C++ dialect called AspectC++ [ Spinczyk05 ], we don’t evaluate in this work its ability to combine AOP and CRTP since it requires its own compiler extensions and so its not standard C++. Here we look at a simple solution implemented in standard C++ that addresses the issue without any overhead penalty.
Problems combining AOP + CRTP
There are some situations where combining the benefits of AOP and CRTP are desirable; however, as we will show below, some problems arise when applying together the individual standard procedures of each technique.
The code in Listing 1 shows an attempt of adding functionality, through aspects, to a base class named
Number
.
//basic class class Number { protected: UnderlyingType n; }; //aspects template <class NextAspect> struct ArithmeticAspect: public NextAspect { FULLTYPE operator+ (const FULLTYPE& other) const; // What type is FULLTYPE? FULLTYPE operator- (const FULLTYPE& other) const; FULLTYPE& operator+= (const FULLTYPE& other); FULLTYPE& operator-= (const FULLTYPE& other); }; template <class NextAspect> struct LogicalAspect : public NextAspect { bool operator! () const; bool operator&& (const FULLTYPE& other) const; bool operator|| (const FULLTYPE& other) const; }; //decorating Number with aspectual code typedef LogicalAspect <ArithmeticAspect<Number > > MyIntegralType; |
Listing 1 |
We can observe that the return type of ArithmeticAspect’s operator
+
and
-
needs to know the ‘complete type’ (
FULLTYPE
) when trying to extend the base class functionality through operator overloading. We will address this issue in the following sections.
A minimal solution
The basic principle of this solution does not differ in essence from the traditional solution mentioned before.
Problem
Number
takes the place of the last aspect in the aspects list. However,
Number
itself needs to know (as a template template argument) the aspects list, to which it itself belongs, leading to a ‘chicken or egg’ grammatical dilemma.
For example, if
Number
knew the complete type, it could use it as a return type for its operators as shown in Listing 2.
template <template <class> class Aspects> class Number { typedef Aspects<Number<Aspects>> FullType; ... }; ArithmeticAspect<Number<ArithmeticAspect>> |
Listing 2 |
This shows the weaving of a single aspect with CRTP, which works perfectly:
LogicalAspect<ArithmeticAspect<Number<??>>>
On the other hand, this exposes the problem when trying to weave one additional aspect, since it requires a template template argument, which the aspects lists can’t grammatically fulfill as coded above.
We present two solutions: the first being the simplest using C++11’s template alias [ Reis ], and the second using variadic templates (templates that take a variable number of arguments, recently introduced in C++11 [ Gregor ]) as the only C++11’s feature, which in turn, can also be easily implemented in C++98 as well. Both use a common language idiom introduced next, which aims to be used as a library providing a friendly syntax and reduced reusable code.
The proposed language idiom
A possible solution would be to apply some handcrafted per-case base template aliases, as shown below:
//with template alias: template <class T> using LogicalArithmeticAspect = LogicalAspect<ArithmeticAspect<T>>; //without template alias: template <class T> struct LogicalArithmeticAspect { typedef LogicalAspect<ArithmeticAspect<T>> Type; }; and with minor changes in the Number base class’s code, we could write the following declaration: LogicalArithmeticAspect < Number<LogicalArithmeticAspect> >
Although this does the trick it tends to be impractical, and also would increment linearly the number of related lines of code in terms of the amount of combinations to be used, which would cause a copy-paste code bloat.
However, we will look for a more generic way to address this issue, avoiding drone code cloning, and being able to encapsulate the method into a library.
Therefore, in order to provide a user-oriented and easy to use library, we'll use C++11’s new variadic-templates so we can cleanly express our intention: to ‘decorate’ the base class with a list of aspects. An example of what we intend to achieve is shown below:
Decorate<Number>::with<ArithmeticAspect, LogicalAspect>
The skeleton of the
Decorate
class is shown in Listing 3, the details of which will vary in the solutions below.
template <template <template <class> class> class Base> class Decorate { public: template<template <class> class ... Aspects> struct with { //... }; //... private: struct Apply { … }; }; |
Listing 3 |
In both solutions, the
with
nested class and the
Apply
internal helper will have different implementations.
Solution 1: Using C++11’s template alias
In this solution, the
Decorate::with
implementation is as shown in Listing 4, and the internal helper
Apply
structure also uses templates aliases (see Listing 5).
template<template <class> class ... Aspects> struct with { template <class T> using AspectsCombination = typename Apply<Aspects...>::template Type<T>; typedef AspectsCombination <Base<AspectsCombination>> Type; }; |
Listing 4 |
template<template <class> class A1, template <class> class ... Aspects> struct Apply<A1, Aspects...> { template <class T> using Type = A1 <typename Apply <Aspects...>::template Type<T>>; }; |
Listing 5 |
Despite the implementation between the two solutions differing, the purpose is the same and the underlying idea is explained next in the second solution.
Solution 2: Not using C++11’s template alias
In this solution, the
Decorate::with
implementation is as shown in Listing 6.
template<template <class> class ... Aspects> struct with { typedef typename Apply<Aspects...>::Type TypeP; typedef typename TypeP::template Binding < Base<TypeP::template Binding> >::Type Type; }; |
Listing 6 |
Combining aspects
Now that we have a list of aspects, how could we combine them? The solution we propose is to create a
Binder
class, as shown in Listing 7.
struct None { }; template <template <class> class A, class B = None> struct Binder { template <class T> struct Binding { typedef typename Binder<A>::template Binding < typename B::template Binding<T>::Type >::Type Type; }; }; template<template <class> class T> struct Binder<T, None> { template <class P> struct Binding { typedef T<P> Type; }; }; |
Listing 7 |
Binder
encapsulates an aspect (as a template template argument) within a complete type
Binder<Aspect>
. Additionally, it enables us to do a ‘
bind
’ operation to the next aspect or base class, by accessing to the
Binding
inner class.
The way in which
Binder
finally allows us to construct the whole type is shown below.
Binder<ArithmeticAspect, Binder<LogicalAspect>>::Binding<Number>::Type
Let’s analyze step-by-step this listing (from the innermost to the outermost definition):
-
Binder<LogicalAspect>
uses the second definition, it just provides a complete type for the aspect with a possibility to bind to another complete type -
Binder<ArithmeticAspect, Binder<LogicalAspect>>
uses the first definition.The binding generates a
Binder
to theArithmeticAspect
, and binds it toBinder<LogicalAspect>::Binding<T>
generating a template template argument combining both aspects. (In short,Binder
generates a template template argument – combining Arithmetic with Logical aspects – to be used in the base class). -
Finally, the type is injected into the base
Number
class.
Since such an implementation is not immediately obvious, we have provided a simplified version in Listing 8 for illustration.
template <template <class> class A, class B = None> struct Binder { template <class T> struct Binding { typedef Binder<A>::Binding < B::Binding<T>::Type >::Type Type; }; }; |
Listing 8 |
Now we’ve got a
Binder
that implements the weaving of aspects and finally inject them into the base class.
Applying the list of Aspects to the Number class
The only remaining detail is to apply our
Bind
class to the list of aspects. To do this, we define a helper structure called
Apply
, that recursively applies the
Binder
class to each aspect, as shown in Listing 9.
template <template <class> class ... Aspects> struct Apply; template <template <class> class T> struct Apply<T> { typedef Binder<T> Type; }; template<template <class> class A1, template <class> class ... Aspects> struct Apply<A1, Aspects...> { typedef Binder<A1, typename Apply < Aspects... >::Type> Type; }; template<template <class> class ... Aspects> struct with { typedef typename Apply<Aspects...>::Type TypeP; typedef typename TypeP::template Binding < Base<TypeP::template Binding> >::Type Type; }; |
Listing 9 |
We use the
Apply
helper struct to generate a resulting aspect as the weaving of all the given aspects, and inject it to the base class.
Then
::Type
contains the type we needed, and that’s it!
Using the library
The library that implements this idiom provides two tools: the means to obtain the
FullType
, and the means to build it.
Listing 10 shows a way of obtaining the
FullType
with an
Aspect
.
//basic class template <template <class> class Aspects> class Number { typedef Aspects<Number<Aspects>> FullType; //... }; // aspect example template <class NextAspect> struct ArithmeticAspect: public NextAspect { typedef typename NextAspect::FullType FullType; FullType operator+ (const FullType& other) const; // ... }; |
Listing 10 |
Let’s see a final example, using two of the aspects mentioned before:
typedef Decorate<Number>::with<ArithmeticAspect, LogicalAspect>::Type ArithmeticLogicalNumber;
Please note that both solutions presented before expose the same interface so this snippet is equally applicable to them.
C++98 alternative and complete code
The same idea can be implemented using typelists in previous C++ standards, such as C++98.
The complete code of the library and examples both for C++11 and C++98 can be accessed in http://cpp-aop.googlecode.com
Final comments
We think that the solution to the problem exposed in this article could become straightforward by enhancing the language with a reserved keyword to get the full type. We suggest to consider this problem for the next revision of the language standard.
References
[Abrahams04] Abrahams, David; Gurtovoy, Aleksey. 2004. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond . Addison-Wesley. ISBN 0-321-22725-5.
[Gregor] Gregor, Douglas; Järvi, Jaako; Powell, Gary. Variadic Templates (Revision 3). [N2080=06-0150]. Programming Language C++. Evolution Working Group.
[Kiczales97] Kiczales, Gregor; John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier, and John Irwin (1997). ‘Aspect-Oriented Programming’. Proceedings of the European Conference on Object-Oriented Programming , vol.1241. pp. 220–242.
[Reis] Dos Reis, Gabriel; Stroustrup, Bjarne. Template Aliases (Revision 3). [N2258=07-0118]. Programming Language C++. Evolution Working Group.
[Spinczyk05] Spinczyk, Olaf; Lohmann, Daniel; Urban, Matthias. ‘AspectC++: an AOP Extension for C++’. Software Developer’s Journal , pages 68-76, 05/2005.