#include <iostream>
#include <memory>
using namespace std;
template< typename T, typename TProlog, typename TEpilog ,
bool call_epilog_due_to_prolog_exeption=true>
class decorator
{
TProlog prolog;
struct TDeleter
{
std::shared_ptr<T> ptr;
TEpilog epilog;
void operator() (T*p)
{
// assert( p == ptr.get() )
epilog();
}
} deleter;
public:
decorator(std::shared_ptr<T> ptr, TProlog prolog, TEpilog epilog)
: prolog(prolog), deleter({ptr, epilog })
{}
decorator(const decorator&) = default;
decorator(decorator&&) = default;
std::shared_ptr<T> operator->() const
{
return get();
}
std::shared_ptr<T> get() const
{
if(call_epilog_due_to_prolog_exeption)
{
std::shared_ptr<T> result( deleter.ptr.get(), deleter );
prolog();
return result;
}
else
{
prolog();
std::shared_ptr<T> result( deleter.ptr.get(), deleter );
return result;
}
}
};
template< typename T, typename TProlog, typename TEpilog >
decorator<T,TProlog,TEpilog>
decorate_ptr(std::shared_ptr<T> ptr, TProlog prolog, TEpilog epilog)
{
return decorator<T,TProlog,TEpilog>(ptr, prolog, epilog);
}
template< typename T, typename TProlog, typename TEpilog >
decorator<T,TProlog,TEpilog>
decorate_obj(T& obj, TProlog prolog, TEpilog epilog)
{
std::shared_ptr<T> ptr( &obj, [](void*){} ); // no call 'delete'
return decorator<T,TProlog,TEpilog>(ptr, prolog, epilog);
}
class FooTest
{
public:
void foo()
{
std::cout << "foo()" << std::endl;
}
} foo_test;
int main()
{
auto foo_ptr = decorate_obj(foo_test,
[](){ std::cout<<"prolog()"<<std::endl; } ,
[](){ std::cout<<"epilog()"<<std::endl; } );
foo_ptr->foo();
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCiAgICB0ZW1wbGF0ZTwgdHlwZW5hbWUgVCwgdHlwZW5hbWUgVFByb2xvZywgdHlwZW5hbWUgVEVwaWxvZyAsCiAgICAgICAgICAgICAgYm9vbCBjYWxsX2VwaWxvZ19kdWVfdG9fcHJvbG9nX2V4ZXB0aW9uPXRydWU+CiAgICBjbGFzcyBkZWNvcmF0b3IKICAgIHsKICAgICAgICBUUHJvbG9nIHByb2xvZzsKICAgICAgICBzdHJ1Y3QgVERlbGV0ZXIKICAgICAgICB7CiAgICAgICAgICAgIHN0ZDo6c2hhcmVkX3B0cjxUPiBwdHI7CiAgICAgICAgICAgIFRFcGlsb2cgZXBpbG9nOwogICAgICAgICAgICB2b2lkIG9wZXJhdG9yKCkgKFQqcCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy8gYXNzZXJ0KCBwID09IHB0ci5nZXQoKSApCiAgICAgICAgICAgICAgICBlcGlsb2coKTsKICAgICAgICAgICAgfQogICAgICAgIH0gZGVsZXRlcjsKCiAgICBwdWJsaWM6CiAgICAgICAgZGVjb3JhdG9yKHN0ZDo6c2hhcmVkX3B0cjxUPiBwdHIsIFRQcm9sb2cgcHJvbG9nLCBURXBpbG9nIGVwaWxvZykKICAgICAgICAgICAgOiBwcm9sb2cocHJvbG9nKSwgZGVsZXRlcih7cHRyLCBlcGlsb2cgfSkKICAgICAgICB7fQogICAgICAgIGRlY29yYXRvcihjb25zdCBkZWNvcmF0b3ImKSA9IGRlZmF1bHQ7CiAgICAgICAgZGVjb3JhdG9yKGRlY29yYXRvciYmKSA9IGRlZmF1bHQ7CgogICAgICAgIHN0ZDo6c2hhcmVkX3B0cjxUPiBvcGVyYXRvci0+KCkgY29uc3QKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiBnZXQoKTsKICAgICAgICB9CgogICAgICAgIHN0ZDo6c2hhcmVkX3B0cjxUPiBnZXQoKSBjb25zdAogICAgICAgIHsKICAgICAgICAgICAgaWYoY2FsbF9lcGlsb2dfZHVlX3RvX3Byb2xvZ19leGVwdGlvbikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgc3RkOjpzaGFyZWRfcHRyPFQ+IHJlc3VsdCggZGVsZXRlci5wdHIuZ2V0KCksIGRlbGV0ZXIgKTsKICAgICAgICAgICAgICAgIHByb2xvZygpOwogICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHByb2xvZygpOwogICAgICAgICAgICAgICAgc3RkOjpzaGFyZWRfcHRyPFQ+IHJlc3VsdCggZGVsZXRlci5wdHIuZ2V0KCksIGRlbGV0ZXIgKTsKICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIHRlbXBsYXRlPCB0eXBlbmFtZSBULCB0eXBlbmFtZSBUUHJvbG9nLCB0eXBlbmFtZSBURXBpbG9nID4KICAgIGRlY29yYXRvcjxULFRQcm9sb2csVEVwaWxvZz4KICAgIGRlY29yYXRlX3B0cihzdGQ6OnNoYXJlZF9wdHI8VD4gcHRyLCBUUHJvbG9nIHByb2xvZywgVEVwaWxvZyBlcGlsb2cpCiAgICB7CiAgICAgICAgcmV0dXJuIGRlY29yYXRvcjxULFRQcm9sb2csVEVwaWxvZz4ocHRyLCBwcm9sb2csIGVwaWxvZyk7CiAgICB9CgogICAgdGVtcGxhdGU8IHR5cGVuYW1lIFQsIHR5cGVuYW1lIFRQcm9sb2csIHR5cGVuYW1lIFRFcGlsb2cgPgogICAgZGVjb3JhdG9yPFQsVFByb2xvZyxURXBpbG9nPgogICAgZGVjb3JhdGVfb2JqKFQmIG9iaiwgVFByb2xvZyBwcm9sb2csIFRFcGlsb2cgZXBpbG9nKQogICAgewogICAgICAgIHN0ZDo6c2hhcmVkX3B0cjxUPiBwdHIoICZvYmosIFtdKHZvaWQqKXt9ICk7IC8vIG5vIGNhbGwgJ2RlbGV0ZScKICAgICAgICByZXR1cm4gZGVjb3JhdG9yPFQsVFByb2xvZyxURXBpbG9nPihwdHIsIHByb2xvZywgZXBpbG9nKTsKICAgIH0KCgoKICAgIGNsYXNzIEZvb1Rlc3QKICAgIHsKICAgIHB1YmxpYzoKICAgICAgICB2b2lkIGZvbygpCiAgICAgICAgewogICAgICAgICAgICBzdGQ6OmNvdXQgPDwgImZvbygpIiA8PCBzdGQ6OmVuZGw7CiAgICAgICAgfQogICAgfSBmb29fdGVzdDsKCgogICAgaW50IG1haW4oKQogICAgewogICAgICAgIGF1dG8gZm9vX3B0ciA9IGRlY29yYXRlX29iaihmb29fdGVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW10oKXsgIHN0ZDo6Y291dDw8InByb2xvZygpIjw8c3RkOjplbmRsOyAgfSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtdKCl7ICBzdGQ6OmNvdXQ8PCJlcGlsb2coKSI8PHN0ZDo6ZW5kbDsgIH0gKTsKICAgICAgICBmb29fcHRyLT5mb28oKTsKCiAgICAgICAgcmV0dXJuIDA7CiAgICB9Cg==