Basically, the abstract interface from the polymorphic decorator becomes an implicitly defined concept and you nest the types. For example:
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 object generator idiom to make composition easier:
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 don't have a common type to store decorated objects, you need to use some kind of type inference. For example:
auto myCoffee = addSugar(addCream(BasicCoffee()));
myCoffee.print();
Alternatively, use the value you get from the object generators as an rvalue (This can be useful if you are stuck with C++03 - type erasure can also help!):
addSugar(addCream(BasicCoffee())).print();