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
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
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