#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;
}