Static polymorphism -- what's wrong?

S

shablool

Hi all,
Could someone please explain what is wrong with this code (the compiler
complains about "'int_type' is not a member of 'B'"):


struct B;

template <typename DerivedT>
struct A
{
typedef typename DerivedT::int_type int_type;

int_type get(void) const { return 0; }
};


struct B : public A<B>
{
typedef int int_type;
};

int main()
{
B b;
return b.get();
}
 
G

Greg

shablool said:
Hi all,
Could someone please explain what is wrong with this code (the compiler
complains about "'int_type' is not a member of 'B'"):


struct B;

template <typename DerivedT>
struct A
{
typedef typename DerivedT::int_type int_type;

int_type get(void) const { return 0; }
};


struct B : public A<B>
{
typedef int int_type;
};

int main()
{
B b;
return b.get();
}

It seems unlikely that struct A is able to typedef a typedef from one
of its derived classes.

Reversing the typedefs to avoid the circular dependency does fix the
problem:

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();
}

Greg
 
M

mlimber

shablool said:
Hi all,
Could someone please explain what is wrong with this code (the compiler
complains about "'int_type' is not a member of 'B'"):


struct B;

template <typename DerivedT>
struct A
{
typedef typename DerivedT::int_type int_type;

int_type get(void) const { return 0; }
};


struct B : public A<B>
{
typedef int int_type;
};

int main()
{
B b;
return b.get();
}

The problem is that B is not defined yet, but you're trying to use it
in A<B>. You can either do what Greg said, or you can break your B
class apart:

struct BAttributes { typedef int int_type; };

template <class T>
struct A
{
typedef typename T::int_type int_type;
int_type get() const { return 0; }
};

struct B : public A<BAttributes>, public BAttributes {};

int main()
{
B b;
return b.get();
}

Note that the multiple inheritance is technically unnecessary here
since A<> duplicates all its types. You would need it only if there
were additional functions, data, or types that A<> did not "copy". BTW,
an easier way to transfer the contents of BAttributes to A<> would be
to treat it like a policy class:

struct BAttributes { typedef int int_type; };

template <class Attributes>
struct A : public Attributes
{
int_type get() const { return 0; }
};

Cheers! --M
 
P

Puppet_Sock

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
 
M

mlimber

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
 
M

mlimber

mlimber said:
class Derived
: public Base
, public DefaultCreator<Base, Derived>
{
public:
static int GetAssignedID() { return 42; }
// ...
};
[snip]

Oops. Copy-paste-and-simplify error. That function should be:

static int GetID() { return 42; }

Cheers! --M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top