Hi there Having a templatized base class B template<class T> class B ..... is it possible to enforce that a class D can derive from B IF AND ONLY IF the curiously recurring template pattern is applied, that is class D1 : public B<D1> ... // ok, compile class D2 : public B<X> ... // not ok, do not compile ??? Thx Stefan
"Stefan Schild"
Hi there
Having a templatized base class B
template<class T> class B .....
is it possible to enforce that a class D can derive from B IF AND ONLY IF the curiously recurring template pattern is applied, that is
class D1 : public B<D1> ... // ok, compile class D2 : public B<X> ... // not ok, do not compile
???
Thx Stefan
Did you try: template<typename T> class B { BOOST_STATIC_ASSERT( boost::is_base_and_derived::value ); .... }; Gennadiy
Gennadiy Rozental wrote:
"Stefan Schild"
wrote in message news:eg3r7s$bcb$1@sea.gmane.org... Hi there
Having a templatized base class B
template<class T> class B .....
is it possible to enforce that a class D can derive from B IF AND ONLY IF the curiously recurring template pattern is applied, that is
class D1 : public B<D1> ... // ok, compile class D2 : public B<X> ... // not ok, do not compile
???
Thx Stefan
Did you try:
template<typename T> class B { BOOST_STATIC_ASSERT( boost::is_base_and_derived::value ); .... };
This doesn't quite work? At this point, T is incomplete. But, it ought to be possible to put this check inside some member function of B; probably the one that casts *this to T& would be the ideal place. But then it should be pretty much unnecessary as the static_cast will fail if the conversion is not possible. Stefan, can you give more details, i.e. a *real* example where you want it to fail to compile, but it does? Cheers, Ian McCulloch
Ian McCulloch wrote:
Stefan, can you give more details, i.e. a *real* example where you want it to fail to compile, but it does?
I can give you the original design I thought may be possible to improve. It's out of memory so don't hit me if it contains bugs. We have a message factory class that stores and executes message functors. The "DoDispatch" and "Execute" methods needs a pointer to T, because we want to access members of the derived class in the message functor (we want do to something useful...). template<class T> class MessageFunctor { public: void Execute( T* target ) = 0; } template<class T> class MessageFactory { // Contains the logic to store, find and execute // message functors. Something like: public: virtual void Dispatch( T* d, const int key ) { MessageFunctorMap::iterator mf = m_message_map.find(key); if ( mf != m_message_functor_map.end() ) mf->Execute( d ); } private: MessageFunctorMap m_message_functor_map; } If we want to add message dispatching to any class, we apply the CRTP and add a dispatch method that calls DoDispatch with the this pointer: class ControlledClass : public MessageFactory<ControlledClass> { void DoDispatch( const int key ) { DoDispatch( this, key ); } } Now, if we were SURE that the T in the MessageFactory class is equal to ControlledClass, i.e., equal to a derived class, couldn't we get our hands on the this pointer in the MessageFactory class already? We would not need the DispatchMessage method any more... template<class T> class MessageFactory { // Contains the logic to store, find and execute // message functors. Something like: public: virtual void Dispatch( const int key ) { // Make sure that T is equal to ControlledClass, // i.e., that the CRTP was used, so we can use this MessageFunctorMap::iterator mf = m_message_map.find(key); if ( mf != m_message_functor_map.end() ) mf->Execute( this ); } private: MessageFunctorMap m_message_functor_map; } . . . Do I make any sense???
Stefan Schild wrote:
Ian McCulloch wrote:
Stefan, can you give more details, i.e. a *real* example where you want it to fail to compile, but it does?
I can give you the original design I thought may be possible to improve. It's out of memory so don't hit me if it contains bugs.
We have a message factory class that stores and executes message functors. The "DoDispatch" and "Execute" methods needs a pointer to T, because we want to access members of the derived class in the message functor (we want do to something useful...).
template<class T> class MessageFunctor { public: void Execute( T* target ) = 0; }
template<class T> class MessageFactory { // Contains the logic to store, find and execute // message functors. Something like: public:
I guess there is something like
typedef std::map
virtual void Dispatch( T* d, const int key ) { MessageFunctorMap::iterator mf = m_message_map.find(key); if ( mf != m_message_functor_map.end() ) mf->Execute( d ); } private: MessageFunctorMap m_message_functor_map; }
If we want to add message dispatching to any class, we apply the CRTP and add a dispatch method that calls DoDispatch with the this pointer:
class ControlledClass : public MessageFactory<ControlledClass> { void DoDispatch( const int key ) { DoDispatch( this, key ); } }
Now, if we were SURE that the T in the MessageFactory class is equal to ControlledClass, i.e., equal to a derived class, couldn't we get our hands on the this pointer in the MessageFactory class already? We would not need the DispatchMessage method any more...
template<class T> class MessageFactory { // Contains the logic to store, find and execute // message functors. Something like: public: virtual void Dispatch( const int key ) { // Make sure that T is equal to ControlledClass, // i.e., that the CRTP was used, so we can use this MessageFunctorMap::iterator mf = m_message_map.find(key); if ( mf != m_message_functor_map.end() ) mf->Execute( this ); } private: MessageFunctorMap m_message_functor_map; }
In CRTP, the functions are usually not virtual. The ideom is
template<class T>
class MessageFactory
{
public:
typedef T self_type;
self_type& self() { return static_cast
Ian McCulloch
If T does not inherit from MessageFactory<T>, the static_cast inside the self() function will not compile. If you wanted a more informative error message, that would be the place to put the STATIC_ASSERT
BOOST_STATIC_ASSERT doesn't give informative messages. Use BOOST_MPL_ASSERT instead :) -- Dave Abrahams Boost Consulting www.boost-consulting.com
Ian McCulloch
Gennadiy Rozental wrote:
"Stefan Schild"
wrote in message news:eg3r7s$bcb$1@sea.gmane.org... Hi there
Having a templatized base class B
template<class T> class B .....
is it possible to enforce that a class D can derive from B IF AND ONLY IF the curiously recurring template pattern is applied, that is
Did you try:
template<typename T> class B { BOOST_STATIC_ASSERT( boost::is_base_and_derived::value ); .... };
This doesn't quite work? At this point, T is incomplete. But, it ought to be possible to put this check inside some member function of B;
Right.
probably the one that casts *this to T& would be the ideal place. But then it should be pretty much unnecessary as the static_cast will fail if the conversion is not possible.
Right. The assertion (and the cast) will compile anyway even if certain bad things are done: class D1 : public B<D1> ... class D2 : public B<D1> ... There's nothing you can do about the 2nd line, because B<D1> is just as valid there, as far as the compiler is concerned, as it is in the first line. I deal with this by saying there's no way to improve on the check that the static_cast gives you (which is pretty good after all), so you may as well just stop worrying about it :) -- Dave Abrahams Boost Consulting www.boost-consulting.com
How about having B declare its constructors private and make T a friend so it has access? Richard Damon -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Stefan Schild Sent: Thursday, October 05, 2006 4:51 PM To: boost-users@lists.boost.org Subject: [Boost-users] Enforcing CRTP with the MPL? Hi there Having a templatized base class B template<class T> class B ..... is it possible to enforce that a class D can derive from B IF AND ONLY IF the curiously recurring template pattern is applied, that is class D1 : public B<D1> ... // ok, compile class D2 : public B<X> ... // not ok, do not compile ??? Thx Stefan _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (5)
-
David Abrahams
-
Gennadiy Rozental
-
Ian McCulloch
-
Richard Damon
-
Stefan Schild