One of the more annoying things about templates is their requirement of one source file per object definition. You cannot have separate declaration in an header and a definition in separate source file. At the time of template usage ALL its definition must be known. But there is a neat trick I found while reading Doom 3 BFG source code for better template classes maintenance.
I found out, that – in fact its possible to separate template class declaration from its definition. They still need to be well known before usage, but written this way code is much cleaner.
The “standard” way the STL library teaches us to write template classes is a little… long.
template<typename _Type, const unsigned _Len> class CArray{ private: _Type m_Data[_Len]; public: CArray(){ memset(this->m_Data, 0, sizeof(_Type) * _Len); } const unsigned GetLength() const{ return _Len; } const _Type& operator[](const unsigned uIndex) const{ if(uIndex >= _Len){ throw std::exception("Index out of range."); } return this->m_Data[uIndex]; } };
We can make it much cleaner.
//===== DECLARATION ===== template<typename _Type, const unsigned _Len> class CArray{ private: _Type m_Data[_Len]; public: CArray(); const unsigned GetLength() const; const _Type& operator[](const unsigned uIndex) const; }; //===== DEFINITION ===== template<typename _Type, const unsigned _Len> CArray<_Type, _Len>::CArray(){ memset(this->m_Data, 0, sizeof(_Type) * _Len); } template<typename _Type, const unsigned _Len> const unsigned CArray<_Type, _Len>::GetLength() const{ return _Len; } template<typename _Type, const unsigned _Len> const _Type& CArray<_Type, _Len>::operator[](const unsigned uIndex) const{ if(uIndex >= _Len){ throw std::exception("Index out of range."); } return this->m_Data[uIndex]; }
On the downside we end up with a little more code, but the advantage of greater future maintainability and the fact that this code doesn’t screw up VS Intellisense out-weights that.