Puppet_Sock said:
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<AbstractClass> Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK( SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass );
// 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<AbstractClass>( new ConcreteClass );
}
private:
typedef Singleton< Factory<AbstractClass> > 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,ConcreteClass>::m_registered =
DefaultCreator<AbstractClass,ConcreteClass>::theFactory::Instance()
.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