Reputation: 1262
There's something not clear to me i wish to put under your attention, please check those code snippets:
template< typename DerivedClass >
class construction_management
{
city* this_city;
public:
construction_management()
{
this_city = static_cast< city* >(this);
}
~construction_management();
};
I removed intentionally all the not necessary code, please look at the constructor which make a static cast of the 'this' pointer to a type 'city', which is defined as below:
class city : public construction_management< city >
{
public:
public:
city( const string& name, const string& owner );
};
The class is intentionally empty, since i think nothing it can contain is relevant here. Want i'm not able to understand at 100% is what is happening here, g++ 4.7.2 prints not warning or error during the compiling phase, and whenever i use the 'this_city' pointer i can access all the public members of city, the object itself looks consistent since all the variables are properly initialized and contain always valid data.
What i wish to know, is why this code does not work if i define construction_management as a plain non-template class? The cast fails due to a conversion tentative from const to non const pointer to city, why?
This is the error print:
game.hpp: In constructor 'city_manager::construction_management::construction_management()':
game.hpp:164:41: error: invalid static_cast from type 'city_manager::construction_management* const' to type 'city_manager::city*'
And why work if construction_management is a template? Is this a kind of CRTP?
Thank you all.
Upvotes: 1
Views: 2728
Reputation: 1236
It's CRTP and it works because of lazy template instantiation.
The line:
this_city = static_cast< city* >(this);
Requires this
to be convertible to a city*
. That does work if city
is derived from construction_management
. However, base classes must have complete declarations before derived classes, so there is only one way to write that:
//template code may or may not be present
class construction_management {...};
//maybe more code here
class city: public construction_management {...};
If the base class is not a template, it is instanced when the compiler first sees the code. Then the compiler runs into the constructor, it doesn't know at that point that city
is derived from construction_management
(or even what a city
is, if it hasn't been declared as an incomplete type), and gives up.
However, if the base class is a template, it is instanced when inheritance is declared (somewhere around that time anyway, I'm not an expert on this). At that point, the compiler knows that city
is derived from construction_management<city>
, and everything works.
For the same reasons, it also works without a template if you move the constructor definition to a file which is compiled later (most likely from the .h to the .cpp).
Upvotes: 5