#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 ...T>
struct MultiBases {};
template <typename ...T>
class CallUp<MultiBases<T...>> : public CallUp<T>...
{
public:
template <typename Derived, typename Op>
CallUp(Op&& op, Derived& obj) : CallUp<T>(op, obj)...
{}
};
template <typename ...T>
class ConstCallUp<MultiBases<T...>> : public ConstCallUp<T>...
{
public:
template <typename Derived, typename Op>
ConstCallUp(Op&& op, Derived& obj) : ConstCallUp<T>(op, 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 Foo01
{
public:
using Base = NoBase;
virtual void reset()
{
std::cout << "reset Foo01\n";
}
void print() const
{
std::cout << "Foo01\n";
}
};
class Foo02
{
public:
using Base = NoBase;
void reset()
{
std::cout << "reset Foo02\n";
}
void print() const
{
std::cout << "Foo02\n";
}
};
class Foo1 : public Foo01, public Foo02
{
public:
using Base = MultiBases<Foo01, Foo02>;
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";
}
};
template <typename T>
using object_class_t = std::remove_cv_t<std::remove_reference_t<T>>;
int main() {
Foo2 foo2;
callUp([](auto&& obj){ using ObjClass = object_class_t<decltype(obj)>; obj.ObjClass::reset();}, foo2);
callUp([](auto&& obj){obj.print();}, foo2);
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxmdW5jdGlvbmFsPgoKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgp1c2luZyBHZXRCYXNlVHlwZSA9IHR5cGVuYW1lIFQ6OkJhc2U7Cgp1c2luZyBOb0Jhc2UgPSB2b2lkOwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CmNsYXNzIENhbGxVcDsKCnRlbXBsYXRlIDw+CmNsYXNzIENhbGxVcDxOb0Jhc2U+CnsKcHVibGljOgogICB0ZW1wbGF0ZSA8dHlwZW5hbWUgT3AsIHR5cGVuYW1lIFQ+CiAgIENhbGxVcChPcCYmIGlnbm9yZU9wZXJhdGlvbiwgVCYmIGlnbm9yZU9iamVjdCkge30KfTsKCgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY2xhc3MgQ2FsbFVwIDogcHVibGljIENhbGxVcDxHZXRCYXNlVHlwZTxUPj4KewpwdWJsaWM6CiAJdGVtcGxhdGUgPHR5cGVuYW1lIE9wPgoJQ2FsbFVwKE9wJiYgb3AsIFQmIG9iaikgOiBDYWxsVXA8R2V0QmFzZVR5cGU8VD4+KG9wLCBvYmopLCBvcChzdGQ6OmZvcndhcmQ8T3A+KG9wKSksIG9iaihvYmopCgl7fQoJfkNhbGxVcCgpCgl7CgkJb3Aob2JqKTsKCX0KcHJpdmF0ZToKCXN0ZDo6ZnVuY3Rpb248dm9pZChUJik+IG9wOwoJVCYgb2JqOwp9OwoKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpjbGFzcyBDb25zdENhbGxVcDsKCnRlbXBsYXRlIDw+CmNsYXNzIENvbnN0Q2FsbFVwPE5vQmFzZT4KewpwdWJsaWM6CiAgIHRlbXBsYXRlIDx0eXBlbmFtZSBPcCwgdHlwZW5hbWUgVD4KICAgQ29uc3RDYWxsVXAoT3AmJiBpZ25vcmVPcGVyYXRpb24sIFQmJiBpZ25vcmVPYmplY3QpIHt9Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY2xhc3MgQ29uc3RDYWxsVXAgOiBwdWJsaWMgQ29uc3RDYWxsVXA8R2V0QmFzZVR5cGU8VD4+CnsKcHVibGljOgogCXRlbXBsYXRlIDx0eXBlbmFtZSBPcD4KCUNvbnN0Q2FsbFVwKE9wJiYgb3AsIGNvbnN0IFQmIG9iaikgOiBDb25zdENhbGxVcDxHZXRCYXNlVHlwZTxUPj4ob3AsIG9iaiksIG9wKHN0ZDo6Zm9yd2FyZDxPcD4ob3ApKSwgb2JqKG9iaikKCXt9Cgl+Q29uc3RDYWxsVXAoKQoJewoJCW9wKG9iaik7Cgl9CnByaXZhdGU6CglzdGQ6OmZ1bmN0aW9uPHZvaWQoVCYpPiBvcDsKCWNvbnN0IFQmIG9iajsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSAuLi5UPgpzdHJ1Y3QgTXVsdGlCYXNlcyB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSAuLi5UPgpjbGFzcyBDYWxsVXA8TXVsdGlCYXNlczxULi4uPj4gOiBwdWJsaWMgQ2FsbFVwPFQ+Li4uCnsKcHVibGljOgogCXRlbXBsYXRlIDx0eXBlbmFtZSBEZXJpdmVkLCB0eXBlbmFtZSBPcD4KCUNhbGxVcChPcCYmIG9wLCBEZXJpdmVkJiBvYmopIDogQ2FsbFVwPFQ+KG9wLCBvYmopLi4uCgl7fQp9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUgLi4uVD4KY2xhc3MgQ29uc3RDYWxsVXA8TXVsdGlCYXNlczxULi4uPj4gOiBwdWJsaWMgQ29uc3RDYWxsVXA8VD4uLi4KewpwdWJsaWM6CiAJdGVtcGxhdGUgPHR5cGVuYW1lIERlcml2ZWQsIHR5cGVuYW1lIE9wPgoJQ29uc3RDYWxsVXAoT3AmJiBvcCwgRGVyaXZlZCYgb2JqKSA6IENvbnN0Q2FsbFVwPFQ+KG9wLCBvYmopLi4uCgl7fQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIE9wLCB0eXBlbmFtZSBUPgphdXRvIGNhbGxVcChPcCYmIG9wLCBUJiBvYmopCnsKCXJldHVybiBDYWxsVXA8VD4oc3RkOjpmb3J3YXJkPE9wPihvcCksIG9iaik7Cn0KdGVtcGxhdGUgPHR5cGVuYW1lIE9wLCB0eXBlbmFtZSBUPgphdXRvIGNhbGxVcChPcCYmIG9wLCBjb25zdCBUJiBvYmopCnsKCXJldHVybiBDb25zdENhbGxVcDxUPihzdGQ6OmZvcndhcmQ8T3A+KG9wKSwgb2JqKTsKfQoKY2xhc3MgRm9vMDEKewpwdWJsaWM6Cgl1c2luZyBCYXNlID0gTm9CYXNlOwoJdmlydHVhbCB2b2lkIHJlc2V0KCkKCXsKCQlzdGQ6OmNvdXQgPDwgInJlc2V0IEZvbzAxXG4iOwoJfQoJdm9pZCBwcmludCgpIGNvbnN0Cgl7CgkJc3RkOjpjb3V0IDw8ICJGb28wMVxuIjsKCX0KfTsKCmNsYXNzIEZvbzAyCnsKcHVibGljOgoJdXNpbmcgQmFzZSA9IE5vQmFzZTsKCXZvaWQgcmVzZXQoKQoJewoJCXN0ZDo6Y291dCA8PCAicmVzZXQgRm9vMDJcbiI7Cgl9Cgl2b2lkIHByaW50KCkgY29uc3QKCXsKCQlzdGQ6OmNvdXQgPDwgIkZvbzAyXG4iOwoJfQp9OwoKCmNsYXNzIEZvbzEgOiBwdWJsaWMgRm9vMDEsIHB1YmxpYyBGb28wMgp7CnB1YmxpYzoKCXVzaW5nIEJhc2UgPSBNdWx0aUJhc2VzPEZvbzAxLCBGb28wMj47Cgl2b2lkIHJlc2V0KCkKCXsKCQlzdGQ6OmNvdXQgPDwgInJlc2V0IEZvbzFcbiI7Cgl9Cgl2b2lkIHByaW50KCkgY29uc3QKCXsKCQlzdGQ6OmNvdXQgPDwgIkZvbzFcbiI7Cgl9Cn07CgpjbGFzcyBGb28yIDogcHVibGljIEZvbzEKewpwdWJsaWM6Cgl1c2luZyBCYXNlID0gRm9vMTsKCXZvaWQgcmVzZXQoKQoJewoJCXN0ZDo6Y291dCA8PCAicmVzZXQgRm9vMlxuIjsKCX0KCXZvaWQgcHJpbnQoKSBjb25zdAoJewoJCXN0ZDo6Y291dCA8PCAiRm9vMlxuIjsKCX0KfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgp1c2luZyBvYmplY3RfY2xhc3NfdCA9IHN0ZDo6cmVtb3ZlX2N2X3Q8c3RkOjpyZW1vdmVfcmVmZXJlbmNlX3Q8VD4+OwoKaW50IG1haW4oKSB7CglGb28yIGZvbzI7CgljYWxsVXAoW10oYXV0byYmIG9iail7IHVzaW5nIE9iakNsYXNzID0gb2JqZWN0X2NsYXNzX3Q8ZGVjbHR5cGUob2JqKT47IG9iai5PYmpDbGFzczo6cmVzZXQoKTt9LCBmb28yKTsKCWNhbGxVcChbXShhdXRvJiYgb2JqKXtvYmoucHJpbnQoKTt9LCBmb28yKTsKfQ==