#include <iostream>
#include <memory>
#include <utility>
#include <type_traits>
using namespace std;
template < typename T>
class has_operator
{
typedef char yes;
typedef char no[ 2 ] ;
template < typename I> static I identity( I) ;
template < typename U,U> struct Check;
template < typename C> static yes& test( Check< decltype( identity( & C:: operator - > ) ) ,& C:: operator - > > * ) ;
template < typename C> static no& test( ...) ;
public :
enum { value = sizeof ( test< T> ( 0 ) ) == sizeof ( yes) } ;
} ;
template < class T, bool hasOperator = has_operator< T> :: value >
struct PtrOperator {
T* p;
PtrOperator( T* pp) : p( pp) { }
T* operator- > ( ) const { return p; }
} ;
template < class T>
struct PtrOperator< T,true > {
T* p;
PtrOperator< T,true > ( T* pp) : p( pp) { }
T& operator- > ( ) const { return * p; }
} ;
template < class T, class Pref, class Suf> class Wrap;
template < class T, class Suf>
class Call_proxy : public PtrOperator< T> {
mutable bool own;
Suf suffix;
Call_proxy( T* pp, Suf su) : PtrOperator< T> ( 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) : PtrOperator< T> ( a.p ) , own( true ) , suffix( a.suffix ) { a.own = false ; }
~Call_proxy( ) { if ( own) suffix( ) ; }
} ;
template < class T, class Pref, class Suf>
class Wrap {
T& p;
Pref prefix;
Suf suffix;
public :
Wrap( T& x, Pref pr, Suf su) : p( x) , prefix( pr) , suffix( su) { }
Call_proxy< T,Suf> operator- > ( ) const { prefix( ) ; return Call_proxy< T,Suf> ( & p,suffix) ; }
} ;
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()" ; }
//X* operator->(){return this;}
} ;
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>
{
using Wrap< T,Pref,Suf> :: operator - > ;
Shared( T& obj) : Wrap< T,Pref, Suf> ( obj,Pref( ) , Suf( ) ) { }
} ;
template < class T>
struct Tracer : public Wrap< T,void ( * ) ( ) ,void ( * ) ( ) > {
using Wrap< T,void ( * ) ( ) ,void ( * ) ( ) > :: operator - > ;
Tracer( T& x) : Wrap< T,void ( * ) ( ) ,void ( * ) ( ) > ( x,:: prefix ,:: suffix ) { }
} ;
template < class T> struct Sealed {
T& p;
Sealed( T& x ) : p( x) { }
T* operator- > ( ) { return & p; }
} ;
int main( ) // test program
{
X x;
Sealed< X> xx( x) ;
Shared< Sealed< X>> xxx( xx) ;
Tracer< Shared< Sealed< X>>> xxxx( xxx) ;
auto y = std:: make_shared < X> ( ) ;
Shared< decltype( y) > yy( y) ;
Tracer< decltype( yy) > yyy( yy) ;
xx- > g( ) ;
xxx- > g( ) ;
xxxx- > g( ) ;
y- > g( ) ;
yy- > g( ) ;
yyy- > g( ) ;
std:: cout << has_operator< X> :: value << std:: endl ;
std:: cout << has_operator< Shared< X>> :: value << std:: endl ;
std:: cout << has_operator< Tracer< Shared< X>>> :: value << std:: endl ;
Shared< X> z( x) ;
Tracer< Shared< X>> zz( z) ;
x.g ( ) ;
z- > g( ) ;
zz- > g( ) ;
return 0 ;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgojaW5jbHVkZSA8dXRpbGl0eT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CmNsYXNzIGhhc19vcGVyYXRvcgp7CiAgICB0eXBlZGVmIGNoYXIgeWVzOwogICAgdHlwZWRlZiBjaGFyIG5vWzJdOwoJdGVtcGxhdGUgPHR5cGVuYW1lIEk+IHN0YXRpYyBJIGlkZW50aXR5KEkpOwoKCXRlbXBsYXRlPHR5cGVuYW1lIFUsVT4gc3RydWN0IENoZWNrOwoJdGVtcGxhdGUgPHR5cGVuYW1lIEM+IHN0YXRpYyB5ZXMmIHRlc3QoQ2hlY2s8ZGVjbHR5cGUoaWRlbnRpdHkoJkM6Om9wZXJhdG9yLT4pKSwmQzo6b3BlcmF0b3ItPiA+Kik7CiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgQz4gc3RhdGljIG5vJiB0ZXN0KC4uLik7CgpwdWJsaWM6CiAgICBlbnVtIHsgdmFsdWUgPSBzaXplb2YodGVzdDxUPigwKSkgPT0gc2l6ZW9mKHllcykgfTsKfTsKCgp0ZW1wbGF0ZTxjbGFzcyBULCBib29sIGhhc09wZXJhdG9yID0gaGFzX29wZXJhdG9yPFQ+Ojp2YWx1ZT4Kc3RydWN0IFB0ck9wZXJhdG9yIHsKCVQqIHA7CglQdHJPcGVyYXRvcihUKnBwKSA6IHAocHApIHt9CglUKiBvcGVyYXRvci0+KCkgY29uc3QgeyByZXR1cm4gcDt9Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUPiAKc3RydWN0IFB0ck9wZXJhdG9yPFQsdHJ1ZT57CglUKiBwOwoJUHRyT3BlcmF0b3I8VCx0cnVlPihUKnBwKSA6IHAocHApIHt9CglUJiBvcGVyYXRvci0+KCkgY29uc3QgeyByZXR1cm4gKnA7fQp9OwoKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgIFByZWYsIGNsYXNzIFN1Zj4gY2xhc3MgIFdyYXA7CnRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzIFN1Zj4KY2xhc3MgIENhbGxfcHJveHkgOiBwdWJsaWMgUHRyT3BlcmF0b3I8VD57CgltdXRhYmxlIGJvb2wgb3duOwoJU3VmIHN1ZmZpeDsKCUNhbGxfcHJveHkoVCogcHAsIFN1ZiBzdSkgOiBQdHJPcGVyYXRvcjxUPihwcCkgLCBvd24odHJ1ZSkgLCBzdWZmaXgoc3UpIHsgfSAgLy8gcmVzdHJpY3QgY3JlYXRpb24KCUNhbGxfcHJveHkmIG9wZXJhdG9yPShjb25zdCAgQ2FsbF9wcm94eSYpIDsgIC8vIHByZXZlbnQgYXNzaWdubWVudApwdWJsaWM6Cgl0ZW1wbGF0ZTxjbGFzcyAgVSwgY2xhc3MgIFAsIGNsYXNzIFM+IGZyaWVuZCBjbGFzcyAgV3JhcDsKCUNhbGxfcHJveHkoY29uc3QgIENhbGxfcHJveHkmIGEpIDogUHRyT3BlcmF0b3I8VD4oYS5wKSAsIG93bih0cnVlKSAsIHN1ZmZpeChhLnN1ZmZpeCkgeyBhLm93bj1mYWxzZTsgfQoJfkNhbGxfcHJveHkoKSB7IGlmIChvd24pIHN1ZmZpeCgpIDsgfQp9OwoKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgIFByZWYsIGNsYXNzIFN1Zj4KY2xhc3MgIFdyYXAgewoJVCYgcDsKCVByZWYgcHJlZml4OwoJU3VmIHN1ZmZpeDsKcHVibGljOgoJV3JhcChUJiB4LCAgUHJlZiBwciwgU3VmIHN1KSA6cCh4KSAsIHByZWZpeChwcikgLCBzdWZmaXgoc3UpIHsgfQoJQ2FsbF9wcm94eTxULFN1Zj4gb3BlcmF0b3ItPigpIGNvbnN0eyBwcmVmaXgoKSA7IHJldHVybiAgQ2FsbF9wcm94eTxULFN1Zj4oJnAsc3VmZml4KSA7IH0KfTsKCmNsYXNzIFggIHsgLy8gb25lIHVzZXIgY2xhc3MKcHVibGljOgoJWCgpIHsgY291dCA8PCAiIG1ha2UgYW4gIFhcbiI7IH0KCX5YKCkgeyBjb3V0IDw8ICJkZXN0cm95IGFuICBYXG4iOyB9CglpbnQgZigpIGNvbnN0eyBjb3V0IDw8ICJmKCkiOyByZXR1cm4gMTsgfQoJdm9pZCBnKCkgY29uc3R7IGNvdXQgPDwgImcoKSI7IH0KCgkvL1gqIG9wZXJhdG9yLT4oKXtyZXR1cm4gdGhpczt9Cn07Cgp2b2lkIHByZWZpeCgpIHsgY291dCA8PCAicHJlZml4ICI7IH0Kdm9pZCBzdWZmaXgoKSB7IGNvdXQgPDwgIiBzdWZmaXhcbiI7IH0KCnN0cnVjdCAgUHJlZiB7IHZvaWQgb3BlcmF0b3IoKSgpIGNvbnN0eyBjb3V0PDwgIiBQcmVmICI7IH0gfTsKc3RydWN0IFN1ZiB7IHZvaWQgb3BlcmF0b3IoKSgpIGNvbnN0eyBjb3V0PDwgIiBTdWYgIjsgfSB9OwoKdGVtcGxhdGU8Y2xhc3MgVD4Kc3RydWN0IFNoYXJlZCA6IHB1YmxpYyAgV3JhcDxULFByZWYsIFN1Zj4KewoJdXNpbmcgV3JhcDxULFByZWYsU3VmPjo6b3BlcmF0b3ItPjsKCVNoYXJlZChUJiBvYmopIDogIFdyYXA8VCxQcmVmLCBTdWY+KG9iaixQcmVmKCkgLCBTdWYoKSkgeyB9Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUPgpzdHJ1Y3QgVHJhY2VyIDogcHVibGljICBXcmFwPFQsdm9pZCgqKSgpICx2b2lkKCopKCk+IHsKCXVzaW5nIFdyYXA8VCx2b2lkKCopKCkgLHZvaWQoKikoKT46Om9wZXJhdG9yLT47CglUcmFjZXIoVCYgeCkgOiAgV3JhcDxULHZvaWQoKikoKSAsdm9pZCgqKSgpPih4LDo6cHJlZml4LDo6c3VmZml4KSB7IH0KfTsKCgoKdGVtcGxhdGU8Y2xhc3MgVD4gc3RydWN0IFNlYWxlZCB7CglUJnA7CglTZWFsZWQoVCZ4ICkgOiBwKHgpe30KCVQqIG9wZXJhdG9yLT4oKSB7cmV0dXJuICZwO30KfTsKCmludCAgbWFpbigpICAvLyB0ZXN0IHByb2dyYW0KewoJWCB4OwoJU2VhbGVkPFg+IHh4KHgpOwoJU2hhcmVkPFNlYWxlZDxYPj4geHh4KHh4KSA7CglUcmFjZXI8U2hhcmVkPFNlYWxlZDxYPj4+IHh4eHgoeHh4KTsKCQoJYXV0byB5ID0gc3RkOjptYWtlX3NoYXJlZDxYPigpOwoJU2hhcmVkPGRlY2x0eXBlKHkpPiB5eSh5KTsKCVRyYWNlcjxkZWNsdHlwZSh5eSk+eXl5KHl5KTsKCQoJeHgtPmcoKTsKCXh4eC0+ZygpOwoJeHh4eC0+ZygpOwoJCgl5LT5nKCk7Cgl5eS0+ZygpOwoJeXl5LT5nKCk7CgoJc3RkOjpjb3V0IDw8IGhhc19vcGVyYXRvcjxYPjo6dmFsdWUgPDwgc3RkOjogZW5kbDsKCXN0ZDo6Y291dCA8PCBoYXNfb3BlcmF0b3I8U2hhcmVkPFg+Pjo6dmFsdWUgPDwgc3RkOjogZW5kbDsKCXN0ZDo6Y291dCA8PCBoYXNfb3BlcmF0b3I8VHJhY2VyPFNoYXJlZDxYPj4+Ojp2YWx1ZSA8PCBzdGQ6OiBlbmRsOwoKCVNoYXJlZDxYPiB6KHgpIDsKCVRyYWNlcjxTaGFyZWQ8WD4+IHp6KHopOwoKCXguZygpOwoJei0+ZygpOwoJenotPmcoKTsKCglyZXR1cm4gMDsKfQ==