Monday, January 9, 2012

Type conversion using template functions

Yesterday I came up with a new way to make type conversions prettier.
I want to explain you how that works in this post.

As you might know, I work with a component based object model in my engine (see here).
In this kind of object model, you sometimes need to modify the component of certain objects after you added them.

To do that I implement a getComponent() function, which - in the past - returned a object of the type of the component interface (called IComponent). Type conversions needed to be made afterwards to work with the desired implementation. That used to look like this:

 GameObject gameobject;  
 RenderableComponent *renderableComponent = new RenderableComponent("graphic.png");  
 gameobject.addComponent(renderableComponent);  
 //Somewhere else in the code in another function.  
 IComponent *component = gameobject.getComponent("RenderableComponent");  
 RenderableComponent *renderableComponent = static_cast<RenderableComponent*>(component);  
 //.. do stuff with renderablecomponent.  

I found that code pretty ugly and unnecessary complicated, so I thought of another idea to do that user friendlier. The first step I did was to change the getComponent() function to a template function.

The function looked like this:

 IComponent *GameObject::getComponent(const String &componentName){  
      for(std::list<IComponent*>::iterator i = this->m_components.begin();i != this->m_components.end();i++){  
           if((*i)->getType() == componentName){  
                return (*i);  
           }  
      }  
      return NULL;
 }  

With template support it now looks like this:
 template<class T>  
 T *getComponent(const String &componentName){  
      for(std::list<IComponent*>::iterator i = m_components.begin();i != m_components.end();i++){  
           if((*i)->getType() == componentName){  
                return static_cast<T*>((*i));  
           }  
      }  
      return NULL;  
 }  
(Hint: If you don't know nothing about template functions, check here)

As you can see, the user determines the return type via the template type ( So there's no ugly conversion needed afterwards.)

The result is (in my opinion) much nicer source code.
The following is the above example reused with the new getComponent() template function:
  GameObject gameobject;   
  RenderableComponent *renderableComponent = new RenderableComponent("graphic.png");   
  gameobject.addComponent(renderableComponent);   
  //Somewhere else in the code in another function.   
  //IComponent *component = gameobject.getComponent("RenderableComponent");   
  //RenderableComponent *renderableComponent = static_cast<RenderableComponent*>(component);  
 RenderableComponent *renderableComponent = gameobject.getComponent<RenderableComponent>("RenderableComponent");   
  //.. do stuff with renderablecomponent.   
I don't know what about you, but I find it much nicer ;) .

Compared with a macro like:
 #define GET_COMPONENT(type)(getComponent<type>(#type))  

The example could even get more improved to look like this:
  GameObject gameobject;    
  RenderableComponent *renderableComponent = new RenderableComponent("graphic.png");    
  gameobject.addComponent(renderableComponent);    
  //Somewhere else in the code in another function.    
  //IComponent *component = gameobject.getComponent("RenderableComponent");    
  //RenderableComponent *renderableComponent = static_cast<RenderableComponent*>(component);   
  RenderableComponent *renderableComponent = gameobject.GET_COMPONENT(RenderableComponent);  
  //.. do stuff with renderablecomponent.    

No comments:

Post a Comment