Puppet_Sock wrote:
Greg wrote:
[snip context] struct B;
template <typename DerivedT>
struct A
{
typedef int int_type;
int_type get() const { return 0; }
};
struct B : public A<B>
{
using A<B>::int_type ;
};
int main()
{
B b;
return b.get();
}
Ok, that freaks me out. I'd never have thought that you
could derive a class from a template of the same class.
I guess it's because, in this case, A<> only refers to
DerivedT in ways that only need the forward declaration.
If you were to, for example, include a data member in A<>
of type DerivedT, then it would bust. (And the compiler
I use agrees, for what that's worth.)
Socks
I use that technique for automatic registration with a factory object.
Assuming Factory<> and Singleton<> classes as found in _Modern C++
Design_'s Loki, I have this in a header file:
// Helper classes for object creation by a factory with a default
// ctor. Concrete classes must implement a static function GetID().
template<class AbstractClass, class ConcreteClass>
class DefaultCreator
{
public:
static std::auto_ptr<A bstractClass> Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK( SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_s uper_and_subcla ss );
// While the factory will also check at run-time to see if a class
// is registered, we assert on m_registered here to cause a link-
// time failure if we forget to register a concrete command class.
assert( m_registered );
return std::auto_ptr<A bstractClass>( new ConcreteClass );
}
private:
typedef Singleton< Factory<Abstrac tClass> > theFactory;
static const bool m_registered;
};
// Automatically register all classes that inherit from
// DefaultCreator< >. (Note that these static members appear in header
// file because they are themselves templates. The compiler will
// ensure that there is only one instance of each globally.)
template<class AbstractClass, class ConcreteClass>
const bool DefaultCreator< AbstractClass,C oncreteClass>:: m_registered =
DefaultCreator< AbstractClass,C oncreteClass>:: theFactory::Ins tance()
.Register( ConcreteClass:: GetID(), ConcreteClass:: Create );
And I use it like so:
class Base {};
class Derived
: public Base
, public DefaultCreator< Base, Derived>
{
public:
static int GetAssignedID() { return 42; }
// ...
};
Then the stuff _Modern C++ Design_ does to register classes with the
factory is automatic for any class inheriting from DefaultCreator< >.
Cheers! --M