#include <iostream>
#include <iomanip>
#include <memory>
using namespace std;

template<typename FROM, typename TO>
class Adapter
{
public:
    /**
     * Adapts something from one type to a type. 
     * @param f
     * @return
     */
    virtual TO adapt(FROM f) = 0;
    
    /**
     * Chains adapters. 
     * 
     * @param <NEXT>
     * @param next 
     * @return a new adapter that takes the output of this adapter and 
     * adapts to something of type NEXT.
     */
    template<typename NEXT>
    std::unique_ptr<Adapter<FROM, NEXT>> chain(Adapter<TO, NEXT> *next)
    {
    	class ChainedAdapter : public Adapter<FROM, NEXT>
    	{
    	private:
	        Adapter<FROM, TO> *x; 
    	    Adapter<TO, NEXT> *next;
    	public:
        	ChainedAdapter(Adapter<FROM, TO> *x, Adapter<TO, NEXT> *next)
            	: x(x), next(next) {}

	        NEXT adapt(FROM f) override {
    	        return next->adapt(x->adapt(f));
        	}
	    };

		//return std::make_unique<ChainedAdapter>(this, next);
		return std::unique_ptr<ChainedAdapter>(new ChainedAdapter(this, next));
    }
};

class CharIntAdapter : public Adapter<char, int>
{
public:
	int adapt(char f) override {
		int ret = static_cast<int>(f);
		cout << "char('" << f << "') -> int(" << ret << ")" << endl;
		return ret;
	}
};

class IntBoolAdapter : public Adapter<int, bool>
{
public:
	bool adapt(int f) override {
		bool ret = f != 0;
		cout << "int(" << f << ") -> bool(" << boolalpha << ret << ")" << endl;
		return ret;
	}
};

int main() {
	CharIntAdapter cia;
	cout << cia.adapt('a') << endl;
	
	cout << endl;
	
    IntBoolAdapter iba;
	cout << boolalpha << cia.chain(&iba)->adapt('a') << endl;

	return 0;
}