Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CRTP - incomplete type .... used in nested name specifier

14 views
Skip to first unread message

Frank Bergemann

unread,
Jun 27, 2009, 8:33:43 AM6/27/09
to
Hi,

i have a problem with applying CRTP.
Here is a short example, which demonstrate it:

========= base.h ==========
template <typename TYPE>
class Base
{
public:
Base()
{ /* void */ }

virtual ~Base()
{ /* void */ }

char buff[TYPE::MAX - TYPE::MIN + 1];
};

========== test.cc ==========
#include "base.h"


class Sample : public Base<Sample>
{
public:
Sample()
: Base<Sample>()
{ /* void */ }

~Sample()
{ /* void */ }

typedef enum {
MIN = 0,
MAX = 10
} Internal_t;
};

int main(int, char**)
{
return 0;
}

-----------------------------------------------

Compilation raises an error:

frank@charlie:~/TEST$ /usr/bin/g++ -o test test.cc
base.h: In instantiation of 'Base<Sample>':
test.cc:5: instantiated from here
base.h:13: error: incomplete type 'Sample' used in nested name
specifier
base.h:13: error: incomplete type 'Sample' used in nested name
specifier
base.h:13: error: array bound is not an integer constant

I could do a workaround and switch to std::vector<char> and allocate
in c'tor via some Sample::getSize().
But i wonder, if there is really no way to use the enum values in the
template base class?
(and if so: why?)

- many thanks!

rgds,
Frank

Bo Persson

unread,
Jun 27, 2009, 12:03:31 PM6/27/09
to

The compiler is correct. At the line

class Sample : public Base<Sample>

the Sample class is not complete, so its content isn't known yet.

Technically you also have the problem that sizeof(Sample) depends on
sizeof(Base), which depends on Sample's enum. That's not going to
work!

>
> I could do a workaround and switch to std::vector<char> and allocate
> in c'tor via some Sample::getSize().

Or pass it as a parameter to the Base constructor.


Bo Persson


Frank Bergemann

unread,
Jun 27, 2009, 3:20:20 PM6/27/09
to Bo Persson
Hi Bo,

Bo Persson schrieb:


>> -----------------------------------------------
>>
>> Compilation raises an error:
>>
>> frank@charlie:~/TEST$ /usr/bin/g++ -o test test.cc
>> base.h: In instantiation of 'Base<Sample>':
>> test.cc:5: instantiated from here
>> base.h:13: error: incomplete type 'Sample' used in nested name
>> specifier
>> base.h:13: error: incomplete type 'Sample' used in nested name
>> specifier
>> base.h:13: error: array bound is not an integer constant
>
> The compiler is correct. At the line
>
> class Sample : public Base<Sample>
>
> the Sample class is not complete, so its content isn't known yet.
>
> Technically you also have the problem that sizeof(Sample) depends on
> sizeof(Base), which depends on Sample's enum. That's not going to
> work!
>
>> I could do a workaround and switch to std::vector<char> and allocate
>> in c'tor via some Sample::getSize().
>
> Or pass it as a parameter to the Base constructor.
>
>
> Bo Persson
>

- thanks (once again :-) for your help, Bo!

"in real" life i had a number of type definitions in Sample,
which i wanted to be handled in my template base class.
E.g. it should manage a container of 'Sample'-typed elements.
Therefore i couldn't use the Base constructor for this.
(it wasn't just some (int) size-information).
So i shifted the necessary stuff to some extra SampleCfg class.
And made my Sample class this way:

class Sample : public Base<SampleCfg, Sample>
{
typedef SampleCfg Cfg;
[...]
};

But another thing i recognized for this:
If i map in some enum type:

class Sample : public Base<SampleCfg, Sample>
{
typedef SampleCfg Cfg;

typedef Cfg::MyEnum_t MyEnum_t;
[...]
};

Then i can't access the MyEnum_t's literals as Sample::FIRST_VAL (e.g.).
But i have to use Sample::Cfg::FIRST_VAL.

Why doesn't the
typedef Cfg::MyEnum_t MyEnum_t;

... within class Sample also "adopt" the names of MyEnum_t elements into
class Sample?

TIA!

cheers,
Frank

0 new messages