Basically, the abstract interface from a polymorphic decorator becomes an implicitly defined concept, and you insert types. For instance:
struct BasicCoffee { void print() {std::cout << "Coffee!\n";} }; template <class T> struct CreamDecorator { CreamDecorator(T x) : mNested(x) {} void print() {mNested.print(); std::cout << "..with cream!\n";} T mNested; }; template <class T> struct SugarDecorator { SugarDecorator(T x) : mNested(x) {} void print() {mNested.print(); std::cout << "..with sugar!\n";} T mNested; };
You probably want to use the identifier of the object generator to simplify the layout:
template <class T> CreamDecorator<T> addCream(T x) {return CreamDecorator<T>(x);} template <class T> SugarDecorator<T> addSugar(T x) {return SugarDecorator<T>(x);}
Since you do not have a general type for storing decorated objects, you need to use some type of output. For instance:
auto myCoffee = addSugar(addCream(BasicCoffee())); myCoffee.print();
Alternatively, use the value that you get from object generators like rvalue (this can be useful if you are stuck with erasure like C ++ 03, it can also help!):
addSugar(addCream(BasicCoffee())).print();
ltjax source share