#include <iostream>
#include <sstream>

struct Statement;
struct Logger;
struct ComponentBase;

//------------------------------------------------------------------------------

struct ComponentBase {
	mutable ComponentBase *next;
	ComponentBase() : next(nullptr) { }
	virtual std::string toString() = 0;
};

template <typename T>
struct Component : ComponentBase {
	T value;
	Component(T value) : value(value) { }
	~Component() { }
	virtual std::string toString() {
		std::stringstream ss;
		ss << value;
		return ss.str();
	}
};

struct ComponentIterator {
	ComponentBase *ptr;
	ComponentIterator(ComponentBase *ptr) : ptr(ptr) { }
	ComponentBase &operator*() { return *ptr; }
	void operator++() { ptr = ptr->next; }
	bool operator!=(ComponentIterator &other) { return (ptr != other.ptr); }
};

//------------------------------------------------------------------------------

struct Statement {
	Logger *logger;
	ComponentBase *front;
	ComponentBase *back;
	ComponentIterator begin() { return front; }
	ComponentIterator end() { return nullptr; }
	
	template <typename T>
	Statement(Logger &logger, Component<T> &component)
	: logger(&logger), front(&component), back(&component) { }
	~Statement();
	
	template <typename T>
	Statement &operator<<(Component<T> &&component) {
		back->next = &component;
		back = &component;
		return *this;
	}
};

//------------------------------------------------------------------------------

struct Logger {
	template <typename T>
	Statement operator<<(Component<T> &&component) {
		return {*this, component};
	}
	
	virtual void log(Statement &statement) = 0;
};

Statement::~Statement() {
	logger->log(*this);
}

//------------------------------------------------------------------------------

template <typename T>
Component<T const &> wrap(T const &value) {
	return value;
}
template <size_t N>
Component<char const *> wrap(char const (&value)[N]) {
	return value;
}

//------------------------------------------------------------------------------

struct MyLogger : public Logger {
	virtual void log(Statement &statement) override {
		for(auto &&component : statement) {
			std::cout << component.toString();
		}
		std::cout << std::endl;
	}
};

int main() {
	std::string variable = "string";
	MyLogger logger;
	logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
}
