#include <iostream>
#include <type_traits>
#include <functional>
template <typename T>
using GetBaseType = typename T::Base;
using NoBase = void;
template <typename T>
class CallUp;
template <>
class CallUp<NoBase>
{
public:
template <typename Op, typename T>
CallUp(Op&& ignoreOperation, T&& ignoreObject) {}
};
template <typename T>
class CallUp : public CallUp<GetBaseType<T>>
{
public:
template <typename Op>
CallUp(Op&& op, T& obj) : CallUp<GetBaseType<T>>(op, obj), op(std::forward<Op>(op)), obj(obj)
{}
~CallUp()
{
op(obj);
}
private:
std::function<void(T&)> op;
T& obj;
};
template <typename T>
class ConstCallUp;
template <>
class ConstCallUp<NoBase>
{
public:
template <typename Op, typename T>
ConstCallUp(Op&& ignoreOperation, T&& ignoreObject) {}
};
template <typename T>
class ConstCallUp : public ConstCallUp<GetBaseType<T>>
{
public:
template <typename Op>
ConstCallUp(Op&& op, const T& obj) : ConstCallUp<GetBaseType<T>>(op, obj), op(std::forward<Op>(op)), obj(obj)
{}
~ConstCallUp()
{
op(obj);
}
private:
std::function<void(T&)> op;
const T& obj;
};
template <typename Op, typename T>
auto callUp(Op&& op, T& obj)
{
return CallUp<T>(std::forward<Op>(op), obj);
}
template <typename Op, typename T>
auto callUp(Op&& op, const T& obj)
{
return ConstCallUp<T>(std::forward<Op>(op), obj);
}
class Foo0
{
public:
using Base = NoBase;
void reset()
{
std::cout << "reset Foo0\n";
}
void print() const
{
std::cout << "Foo0\n";
}
};
class Foo1 : public Foo0
{
public:
using Base = Foo0;
void reset()
{
std::cout << "reset Foo1\n";
}
void print() const
{
std::cout << "Foo1\n";
}
};
class Foo2 : public Foo1
{
public:
using Base = Foo1;
void reset()
{
std::cout << "reset Foo2\n";
}
void print() const
{
std::cout << "Foo2\n";
}
};
int main() {
Foo2 foo2;
callUp([](auto&& obj){obj.reset();}, foo2);
callUp([](auto&& obj){obj.print();}, foo2);
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxmdW5jdGlvbmFsPgoKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgp1c2luZyBHZXRCYXNlVHlwZSA9IHR5cGVuYW1lIFQ6OkJhc2U7CnVzaW5nIE5vQmFzZSA9IHZvaWQ7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY2xhc3MgQ2FsbFVwOwoKdGVtcGxhdGUgPD4KY2xhc3MgQ2FsbFVwPE5vQmFzZT4KewpwdWJsaWM6CiAgIHRlbXBsYXRlIDx0eXBlbmFtZSBPcCwgdHlwZW5hbWUgVD4KICAgQ2FsbFVwKE9wJiYgaWdub3JlT3BlcmF0aW9uLCBUJiYgaWdub3JlT2JqZWN0KSB7fQp9OwoKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpjbGFzcyBDYWxsVXAgOiBwdWJsaWMgQ2FsbFVwPEdldEJhc2VUeXBlPFQ+Pgp7CnB1YmxpYzoKIAl0ZW1wbGF0ZSA8dHlwZW5hbWUgT3A+CglDYWxsVXAoT3AmJiBvcCwgVCYgb2JqKSA6IENhbGxVcDxHZXRCYXNlVHlwZTxUPj4ob3AsIG9iaiksIG9wKHN0ZDo6Zm9yd2FyZDxPcD4ob3ApKSwgb2JqKG9iaikKCXt9Cgl+Q2FsbFVwKCkKCXsKCQlvcChvYmopOwoJfQpwcml2YXRlOgoJc3RkOjpmdW5jdGlvbjx2b2lkKFQmKT4gb3A7CglUJiBvYmo7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY2xhc3MgQ29uc3RDYWxsVXA7Cgp0ZW1wbGF0ZSA8PgpjbGFzcyBDb25zdENhbGxVcDxOb0Jhc2U+CnsKcHVibGljOgogICB0ZW1wbGF0ZSA8dHlwZW5hbWUgT3AsIHR5cGVuYW1lIFQ+CiAgIENvbnN0Q2FsbFVwKE9wJiYgaWdub3JlT3BlcmF0aW9uLCBUJiYgaWdub3JlT2JqZWN0KSB7fQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CmNsYXNzIENvbnN0Q2FsbFVwIDogcHVibGljIENvbnN0Q2FsbFVwPEdldEJhc2VUeXBlPFQ+Pgp7CnB1YmxpYzoKIAl0ZW1wbGF0ZSA8dHlwZW5hbWUgT3A+CglDb25zdENhbGxVcChPcCYmIG9wLCBjb25zdCBUJiBvYmopIDogQ29uc3RDYWxsVXA8R2V0QmFzZVR5cGU8VD4+KG9wLCBvYmopLCBvcChzdGQ6OmZvcndhcmQ8T3A+KG9wKSksIG9iaihvYmopCgl7fQoJfkNvbnN0Q2FsbFVwKCkKCXsKCQlvcChvYmopOwoJfQpwcml2YXRlOgoJc3RkOjpmdW5jdGlvbjx2b2lkKFQmKT4gb3A7Cgljb25zdCBUJiBvYmo7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgT3AsIHR5cGVuYW1lIFQ+CmF1dG8gY2FsbFVwKE9wJiYgb3AsIFQmIG9iaikKewoJcmV0dXJuIENhbGxVcDxUPihzdGQ6OmZvcndhcmQ8T3A+KG9wKSwgb2JqKTsKfQp0ZW1wbGF0ZSA8dHlwZW5hbWUgT3AsIHR5cGVuYW1lIFQ+CmF1dG8gY2FsbFVwKE9wJiYgb3AsIGNvbnN0IFQmIG9iaikKewoJcmV0dXJuIENvbnN0Q2FsbFVwPFQ+KHN0ZDo6Zm9yd2FyZDxPcD4ob3ApLCBvYmopOwp9CgpjbGFzcyBGb28wCnsKcHVibGljOgoJdXNpbmcgQmFzZSA9IE5vQmFzZTsKCXZvaWQgcmVzZXQoKQoJewoJCXN0ZDo6Y291dCA8PCAicmVzZXQgRm9vMFxuIjsKCX0KCXZvaWQgcHJpbnQoKSBjb25zdAoJewoJCXN0ZDo6Y291dCA8PCAiRm9vMFxuIjsKCX0KfTsKCmNsYXNzIEZvbzEgOiBwdWJsaWMgRm9vMAp7CnB1YmxpYzoKCXVzaW5nIEJhc2UgPSBGb28wOwoJdm9pZCByZXNldCgpCgl7CgkJc3RkOjpjb3V0IDw8ICJyZXNldCBGb28xXG4iOwoJfQoJdm9pZCBwcmludCgpIGNvbnN0Cgl7CgkJc3RkOjpjb3V0IDw8ICJGb28xXG4iOwoJfQp9OwoKY2xhc3MgRm9vMiA6IHB1YmxpYyBGb28xCnsKcHVibGljOgoJdXNpbmcgQmFzZSA9IEZvbzE7Cgl2b2lkIHJlc2V0KCkKCXsKCQlzdGQ6OmNvdXQgPDwgInJlc2V0IEZvbzJcbiI7Cgl9Cgl2b2lkIHByaW50KCkgY29uc3QKCXsKCQlzdGQ6OmNvdXQgPDwgIkZvbzJcbiI7Cgl9Cn07CgoKaW50IG1haW4oKSB7CglGb28yIGZvbzI7CgljYWxsVXAoW10oYXV0byYmIG9iail7b2JqLnJlc2V0KCk7fSwgZm9vMik7CgljYWxsVXAoW10oYXV0byYmIG9iail7b2JqLnByaW50KCk7fSwgZm9vMik7Cn0=