The question seems very abstract. I will ask by an example instead.
Assume that I have many types of game objects.
They are Bullet, Rocket, Enemy, Zone, ... .
They are all nicely created & deleted & managed by pools, e.g.
Pool<Bullet> poolBullet ;
Pool<Rocket> poolRocket ;
The game logic would manage object in form of Pool_Handle< xxx >, e.g.
Pool_Handle< Bullet > bullet = poolBullet.create() ;
Pool_Handle< Rocket> rocket = poolRocket .create() ;
Now, I look at the refactoring.
For example, if my old code was ...
Bullet* functionA(Rocket* rocket){
for(int n=0;n<rocket->zones.size();n++){
Zone* zone = rocket->zones.get(n);
Bullet* return_value =zone.functionB();
}
}
... it would become ...
Pool_Handle<Bullet> functionA(Pool_Handle<Rocket> rocket){
for(int n=0;n<rocket->zones.size();n++){
Pool_Handle<Zone> zone = rocket->zones.get(n);
Pool_Handle<Bullet> return_value =zone.functionB();
}
}
Notice that they are now Pool_Handle everywhere.
After reading and editing these thousands line codes for a few days, I have grown accustomed to Pool_Handle even more than any game objects. It might be a word that I type fastest now.
How to retain readability and maintainability to equal level of the old code, and if possible, how to reduce time of typing for the variable template?
I don't expect a perfect answer, because every solution I found has some trade-off.
/** remedy 1 **/
template <class TT> using H = Pool_Handle<TT>; //remedy line
H<Bullet> bullet ; //alleviate symptom, better but not perfect
/** remedy 2 **/
using H_Bullet = Pool_Handle<H_Bullet>; //remedy line
H_Bullet bullet ; //looks good, but have limitations
/** remedy 3 **/
auto bullet; //concise, but can't be used everywhere, sometimes also reduce readability
The second solution seems to be nice, but introduces several limitations.
I have to declare a line for Bullet, Rocket, ... and so on, one by one
If there is a new type of game object, I will have to add another line manually.
If a game object is renamed, e.g. Bullet -> MetalBullet, I will also have to change the remedy line to H_MetalBullet manually.
Therefore, it lowers overall maintainability.
Are there any better approaches?
(Edit) You can assume c++11, c++14, whatever.
(Edit) A platform independent solution is favorable.
In the second solution, I have to add "another" line after declare a new class.
The line is ...
using H_Bullet = Pool_Handle<H_Bullet>;
Where should I place it?
inside Bullet.h ;
It will create bad coupling, because Bullet should not know about the Handle at all.
inside some high-level header that is included by every game logic files ;
The result is that there are 2 different places that has some definitions about Bullet.
More places -> Less maintainability.
Both places will yield a certain minor disadvantage : When I call some automatic refactoring I have to call twice, on both Bullet and H_Bullet.
What's wrong with a header that just forward declares the types you're interested in? It will only change when you add new types to your system that need handles, and if you rename / add something it will break gracefully.
types_fwd.hpp
template <typename> Pool;
template <typename> Pool_Handle;
class Bullet;
class Rocket;
using H_Bullet = Pool_Handle<Bullet>;
using H_Rocket = Pool_Handle<Rocket>;
The only other option would be to invert things and forward declare the pool and handle and include / add that to each header that introduces new types that need handles.