#include <iostream> 
#include <memory> 
#include <type_traits> 
 
struct  TagA { } ; 
struct  TagB { } ; 
 
template <  typename  tp_Derived > 
struct  BaseCRTP; 
 
struct  Base
{ 
	template <  typename  >  friend 
	struct  BaseCRTP; 
 
	private :  void 
	handler_impl( const  std:: shared_ptr < Base>  & )  { } 
} ; 
 
template <  typename  tp_Derived > 
struct  BaseCRTP:  public  Base
{ 
	public :  void 
	handler( const  std:: shared_ptr < Base>  &  obj) 
	{ 
		static_assert
		( 
			:: std :: is_base_of <  TagA, tp_Derived > :: value 
		,	"\" handler\"  method can only be used in classes deriving from TagA" 
		) ; 
		return ( handler_impl( obj) ) ; 
	} 
} ; 
 
struct  DerivedA :  BaseCRTP<  DerivedA > , TagA
{ } ; 
 
struct  DerivedB :  BaseCRTP<  DerivedB > , TagB
{ } ; 
 
int  main( ) 
{ 
	DerivedA a;  // OK 
	( void )  a;  // not used 
	auto  pha( & DerivedA:: handler ) ;  // OK 
	DerivedB b;  // OK 
	( void )  b;  // not used 
	auto  phb( & DerivedB:: handler ) ;  // static_assertion failure 
	return  0 ; 
} 
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CgpzdHJ1Y3QgVGFnQSB7fTsKc3RydWN0IFRhZ0Ige307Cgp0ZW1wbGF0ZTwgdHlwZW5hbWUgdHBfRGVyaXZlZCA+CnN0cnVjdCBCYXNlQ1JUUDsKCnN0cnVjdCBCYXNlCnsKCXRlbXBsYXRlPCB0eXBlbmFtZSA+IGZyaWVuZAoJc3RydWN0IEJhc2VDUlRQOwoKCXByaXZhdGU6IHZvaWQKCWhhbmRsZXJfaW1wbChjb25zdCBzdGQ6OnNoYXJlZF9wdHI8QmFzZT4gJikge30KfTsKCnRlbXBsYXRlPCB0eXBlbmFtZSB0cF9EZXJpdmVkID4Kc3RydWN0IEJhc2VDUlRQOiBwdWJsaWMgQmFzZQp7CglwdWJsaWM6IHZvaWQKCWhhbmRsZXIoY29uc3Qgc3RkOjpzaGFyZWRfcHRyPEJhc2U+ICYgb2JqKQoJewoJCXN0YXRpY19hc3NlcnQKCQkoCgkJCTo6c3RkOjppc19iYXNlX29mPCBUYWdBLCB0cF9EZXJpdmVkID46OnZhbHVlCgkJLAkiXCJoYW5kbGVyXCIgbWV0aG9kIGNhbiBvbmx5IGJlIHVzZWQgaW4gY2xhc3NlcyBkZXJpdmluZyBmcm9tIFRhZ0EiCgkJKTsKCQlyZXR1cm4oaGFuZGxlcl9pbXBsKG9iaikpOwoJfQp9OwoKc3RydWN0IERlcml2ZWRBIDogQmFzZUNSVFA8IERlcml2ZWRBID4sIFRhZ0EKe307CgpzdHJ1Y3QgRGVyaXZlZEIgOiBCYXNlQ1JUUDwgRGVyaXZlZEIgPiwgVGFnQgp7fTsKCmludCBtYWluKCkKewoJRGVyaXZlZEEgYTsgLy8gT0sKCSh2b2lkKSBhOyAvLyBub3QgdXNlZAoJYXV0byBwaGEoJkRlcml2ZWRBOjpoYW5kbGVyKTsgLy8gT0sKCURlcml2ZWRCIGI7IC8vIE9LCgkodm9pZCkgYjsgLy8gbm90IHVzZWQKCWF1dG8gcGhiKCZEZXJpdmVkQjo6aGFuZGxlcik7IC8vIHN0YXRpY19hc3NlcnRpb24gZmFpbHVyZQoJcmV0dXJuIDA7Cn0=