JPGygax68
5/17/2016 - 9:32 PM

Aspects_composition_with_CRTP.cpp

#include <iostream>

/*=======================================================================
 * ASPECT COMPOSITION
 *======================================================================*/

/* This is the base class to be specialized via CRTP.
 * 
 * It must provide all the methods that aspects can override as no-ops.
 */
template<class Class>
struct Base
{
    void tell() {} // no-op, and ends the chain

protected:
    // This is a con
    auto p() { return static_cast<Class*>(this); }
};

/** The aspect composer is a template that uses a classic head/tail setup to recursively
    inherit from all specified ancestors (= aspects).
 */
 
template<class Class, template<class> class ...Aspects> class Aspect_composer;

template<class Class, template<class> class Aspect>
class Aspect_composer<Class, Aspect>: public Aspect< Base<Class> > {};

template<class Class, template<class> class FirstAspect, template<class> class ...OtherAspects>
class Aspect_composer<Class, FirstAspect, OtherAspects...>: public FirstAspect< Aspect_composer<Class, OtherAspects...> > {};

/** Here now come the aspects.
 */
 
template<class Parent>
class Aspect1: public Parent
{
public:
    Aspect1() { std::cout << "Aspect1 here" << std::endl; }
    
    void tell() { 
        auto that = this->p();
        std::cout << "Hello from Aspect1: dummy = " << that->dummy << std::endl;
        Parent::tell(); // chaining to next aspect
    }
};

template<class Parent>
class Aspect2: public Parent
{
public:
    Aspect2() { std::cout << "Aspect2 here" << std::endl; }
    void tell() { 
        auto that = this->p();
        std::cout << "Hello from Aspect2: dummy = " << that->dummy << std::endl;
        Parent::tell(); // chaining
    }
};

template<class Parent>
class Aspect3: public Parent
{
public:
    Aspect3() { std::cout << "Aspect3 here" << std::endl; }
    void tell() { 
        std::cout << "Hello from Aspect3" << std::endl;
        Parent::tell(); // chaining
    }
};

/** Declaring a class that integrates all the aspects is now easy:
 */
class My_class: public Aspect_composer<My_class, Aspect1, Aspect2, Aspect3>
{
private:
    // Every aspect that is supposed to access private/protected stuff must be given access explicitly:    
    friend class Aspect1;   
    friend class Aspect2;
    int dummy = 100;
};

int main()
{
    My_class obj;
    
    obj.tell();
    
    std::cout << std::endl << "Press RETURN to terminate" << std::endl;
    char dummy; std::cin >> std::noskipws >> dummy;

    return 0;
}