#include <iostream>
using namespace std;
template<class T, class Pref, class Suf> class Wrap;
template<class T, class Suf>
class Call_proxy {
T* p;
mutable bool own;
Suf suffix;
Call_proxy(T* pp, Suf su) :p(pp) , own(true) , suffix(su) { } // restrict creation
Call_proxy& operator=(const Call_proxy&) ; // prevent assignment
public:
template<class U, class P, class S> friend class Wrap;
Call_proxy(const Call_proxy& a) : p(a.p) , own(true) , suffix(a.suffix) { a.own=false; }
~Call_proxy() { if (own) suffix() ; }
T* operator->() const{ return p;}
//T& operator->() const{ return *p;}
};
template<class T, class Pref, class Suf>
class Wrap {
T* p;
int* owned;
void incr_owned() const{ if(owned) ++*owned; }
void decr_owned() const{ if(owned && --*owned == 0) { delete p; delete owned; } }
Pref prefix;
Suf suffix;
public:
Wrap(T& x, Pref pr, Suf su) :p(&x) , owned(0) , prefix(pr) , suffix(su) { }
Wrap(T* pp, Pref pr, Suf su) :p(pp) , owned(new int(1)) , prefix(pr) , suffix(su) { }
Wrap(const Wrap& a)
:p(a.p) , owned(a.owned) , prefix(a.prefix) , suffix(a.suffix) { incr_owned() ; }
Wrap& operator=(const Wrap& a)
{
a.incr_owned() ;
decr_owned() ;
p = a.p;
owned = a.owned;
prefix= a.prefix;
suffix= a.suffix;
return *this;
}
~Wrap() { decr_owned() ; }
Call_proxy<T,Suf> operator->() const{ prefix() ; return Call_proxy<T,Suf>(p,suffix) ; }
T* direct() const{ return p; } // extract pointer to wrapped object
};
class X { // one user class
public:
X() { cout << " make an X\n"; }
~X() { cout << "destroy an X\n"; }
int f() const{ cout << "f()"; return 1; }
void g() const{ cout << "g()"; }
};
class Y { // another user class
public:
Y() { cout << " make a Y\n"; }
~Y() { cout << "destroy a Y\n"; }
void h() const{ cout << "h()"; }
};
void prefix() { cout << "prefix "; }
void suffix() { cout << " suffix\n"; }
struct Pref { void operator()() const{ cout<< " Pref "; } };
struct Suf { void operator()() const{ cout<< " Suf "; } };
template<class T>
struct Shared : public Wrap<T,Pref, Suf>
{
Shared(T& obj) : Wrap<T,Pref, Suf>(obj,Pref() , Suf()) { }
};
template<class T>
struct Tracer : public Wrap<T,void(*)() ,void(*)()> {
Tracer(T& x) : Wrap<T,void(*)() ,void(*)()>(x,::prefix,::suffix) { }
};
int main() // test program
{
X x;
Shared<X> xx(x) ;
Tracer<Shared<X>> xxx(xx);
xx->g();
xxx->g();
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgIFByZWYsIGNsYXNzIFN1Zj4gY2xhc3MgIFdyYXA7CnRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzIFN1Zj4KY2xhc3MgIENhbGxfcHJveHkgewoJVCogcDsKCW11dGFibGUgYm9vbCBvd247CglTdWYgc3VmZml4OwoJQ2FsbF9wcm94eShUKiBwcCwgU3VmIHN1KSA6cChwcCkgLCBvd24odHJ1ZSkgLCBzdWZmaXgoc3UpIHsgfSAgLy8gcmVzdHJpY3QgY3JlYXRpb24KCUNhbGxfcHJveHkmIG9wZXJhdG9yPShjb25zdCAgQ2FsbF9wcm94eSYpIDsgIC8vIHByZXZlbnQgYXNzaWdubWVudApwdWJsaWM6Cgl0ZW1wbGF0ZTxjbGFzcyAgVSwgY2xhc3MgIFAsIGNsYXNzIFM+IGZyaWVuZCBjbGFzcyAgV3JhcDsKCUNhbGxfcHJveHkoY29uc3QgIENhbGxfcHJveHkmIGEpIDogcChhLnApICwgb3duKHRydWUpICwgc3VmZml4KGEuc3VmZml4KSB7IGEub3duPWZhbHNlOyB9Cgl+Q2FsbF9wcm94eSgpIHsgaWYgKG93bikgc3VmZml4KCkgOyB9CgoJVCogb3BlcmF0b3ItPigpIGNvbnN0eyByZXR1cm4gcDt9CgkvL1QmIG9wZXJhdG9yLT4oKSBjb25zdHsgcmV0dXJuICpwO30KCQp9OwoKCnRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzICBQcmVmLCBjbGFzcyBTdWY+CmNsYXNzICBXcmFwIHsKCVQqIHA7CglpbnQqIG93bmVkOwoJdm9pZCBpbmNyX293bmVkKCkgY29uc3R7IGlmKG93bmVkKSArKypvd25lZDsgfQoJdm9pZCBkZWNyX293bmVkKCkgY29uc3R7IGlmKG93bmVkICYmIC0tKm93bmVkID09IDApIHsgZGVsZXRlIHA7IGRlbGV0ZSBvd25lZDsgfSB9CglQcmVmIHByZWZpeDsKCVN1ZiBzdWZmaXg7CnB1YmxpYzoKCVdyYXAoVCYgeCwgIFByZWYgcHIsIFN1ZiBzdSkgOnAoJngpICwgb3duZWQoMCkgLCBwcmVmaXgocHIpICwgc3VmZml4KHN1KSB7IH0KCVdyYXAoVCogcHAsICBQcmVmIHByLCBTdWYgc3UpIDpwKHBwKSAsIG93bmVkKG5ldyBpbnQoMSkpICwgcHJlZml4KHByKSAsIHN1ZmZpeChzdSkgeyB9CglXcmFwKGNvbnN0ICBXcmFwJiBhKQoJCTpwKGEucCkgLCBvd25lZChhLm93bmVkKSAsIHByZWZpeChhLnByZWZpeCkgLCBzdWZmaXgoYS5zdWZmaXgpIHsgaW5jcl9vd25lZCgpIDsgfQoJV3JhcCYgb3BlcmF0b3I9KGNvbnN0ICBXcmFwJiBhKQoJewoJCWEuaW5jcl9vd25lZCgpIDsKCQlkZWNyX293bmVkKCkgOwoJCXAgPSBhLnA7CgkJb3duZWQgPSBhLm93bmVkOwoJCXByZWZpeD0gYS5wcmVmaXg7CgkJc3VmZml4PSBhLnN1ZmZpeDsKCQlyZXR1cm4gKnRoaXM7Cgl9Cgl+V3JhcCgpIHsgZGVjcl9vd25lZCgpIDsgfQoJQ2FsbF9wcm94eTxULFN1Zj4gb3BlcmF0b3ItPigpIGNvbnN0eyBwcmVmaXgoKSA7IHJldHVybiAgQ2FsbF9wcm94eTxULFN1Zj4ocCxzdWZmaXgpIDsgfQoJVCogZGlyZWN0KCkgY29uc3R7IHJldHVybiBwOyB9IC8vIGV4dHJhY3QgcG9pbnRlciB0byB3cmFwcGVkIG9iamVjdAp9OwoKY2xhc3MgWCAgeyAvLyBvbmUgdXNlciBjbGFzcwpwdWJsaWM6CglYKCkgeyBjb3V0IDw8ICIgbWFrZSBhbiAgWFxuIjsgfQoJflgoKSB7IGNvdXQgPDwgImRlc3Ryb3kgYW4gIFhcbiI7IH0KCWludCBmKCkgY29uc3R7IGNvdXQgPDwgImYoKSI7IHJldHVybiAxOyB9Cgl2b2lkIGcoKSBjb25zdHsgY291dCA8PCAiZygpIjsgfQp9OwpjbGFzcyBZIHsgLy8gYW5vdGhlciB1c2VyIGNsYXNzCnB1YmxpYzoKCVkoKSB7IGNvdXQgPDwgIiBtYWtlIGEgWVxuIjsgfQoJflkoKSB7IGNvdXQgPDwgImRlc3Ryb3kgYSBZXG4iOyB9Cgl2b2lkIGgoKSBjb25zdHsgY291dCA8PCAiaCgpIjsgfQp9OwoKdm9pZCBwcmVmaXgoKSB7IGNvdXQgPDwgInByZWZpeCAiOyB9CnZvaWQgc3VmZml4KCkgeyBjb3V0IDw8ICIgc3VmZml4XG4iOyB9CgpzdHJ1Y3QgIFByZWYgeyB2b2lkIG9wZXJhdG9yKCkoKSBjb25zdHsgY291dDw8ICIgUHJlZiAiOyB9IH07CnN0cnVjdCBTdWYgeyB2b2lkIG9wZXJhdG9yKCkoKSBjb25zdHsgY291dDw8ICIgU3VmICI7IH0gfTsKCnRlbXBsYXRlPGNsYXNzIFQ+CnN0cnVjdCBTaGFyZWQgOiBwdWJsaWMgIFdyYXA8VCxQcmVmLCBTdWY+CnsKCVNoYXJlZChUJiBvYmopIDogIFdyYXA8VCxQcmVmLCBTdWY+KG9iaixQcmVmKCkgLCBTdWYoKSkgeyB9Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUPgpzdHJ1Y3QgVHJhY2VyIDogcHVibGljICBXcmFwPFQsdm9pZCgqKSgpICx2b2lkKCopKCk+IHsKCVRyYWNlcihUJiB4KSA6ICBXcmFwPFQsdm9pZCgqKSgpICx2b2lkKCopKCk+KHgsOjpwcmVmaXgsOjpzdWZmaXgpIHsgfQp9OwoKaW50ICBtYWluKCkgIC8vIHRlc3QgcHJvZ3JhbQp7CglYIHg7CglTaGFyZWQ8WD4geHgoeCkgOwoJVHJhY2VyPFNoYXJlZDxYPj4geHh4KHh4KTsKCgl4eC0+ZygpOwoJeHh4LT5nKCk7CglyZXR1cm4gMDsKfQ==