#include <iostream>
#include <stack>
#include <memory>

template<typename T>
class Undo : public T {
private:
    std::shared_ptr<std::stack<Undo>> history_ptr = std::make_shared<std::stack<Undo>>();

public:
    template <typename... Args>
    explicit Undo(const Args&... args): T(args ...) {}

    void save() {
        history_ptr->push(*this);
    }

    void undo() {
        if (!history_ptr->empty()) {
            *this = history_ptr->top();
            history_ptr->pop();
        }
    }
};

class Foo {
public:
    int a = 0;
    std::string s;

    Foo(const int _a, std::string _s): a(_a), s(std::move(_s)) {}
};

std::ostream &operator<<(std::ostream &out, const Foo &foo) {
    out << "Foo(" << foo.a << ", \"" << foo.s << "\")";
    return out;
}

int main() {
    Undo<Foo> foo(1, "Hello World!");

    foo.save();
    std::cout << "Save\t" << foo << std::endl;

    foo.a = 6661313;
    foo.save();
    std::cout << "Save\t" << foo << std::endl;

    foo.s = "Lakad Matataaag!";
    foo.save();
    std::cout << "Save\t" << foo << std::endl;

    foo.a = 9000;
    foo.s = "Normalin, Normalin!";
    foo.save();
    std::cout << "Save\t" << foo << std::endl;

    foo.a = 12345678;
    foo.s = "Da next lebel play!";
    std::cout << "Current\t" << foo << std::endl;

    foo.undo();
    std::cout << "Undo\t" << foo << std::endl;

    foo.undo();
    std::cout << "Undo\t" << foo << std::endl;

    foo.undo();
    std::cout << "Undo\t" << foo << std::endl;

    foo.undo();
    std::cout << "Undo\t" << foo << std::endl;

    return 0;
}