// include the header here only for autocompletion
#include "RedBlackTree.h"
// define the static member
template <typename T>
CRedBlackTree<T>::SNode* CRedBlackTree<T>::m_spNil = CRedBlackTree<T>::createNil();
// and its initializer
template <typename T>
CRedBlackTree<T>::SNode*
CRedBlackTree<T>::createNil()
{
CRedBlackTree<T>::m_spNil = new CRedBlackTree<T>::SNode();
CRedBlackTree<T>::m_spNil->color = black;
}
template<typename T>
CRedBlackTree<T>::SNode*
CRedBlackTree<T>::find(const T* element) const
{
// ...
}
The errors occur in lines 6, 10 and 18 of the .cpp file. The error message is always:
error: expected constructor, destructor, or type conversion before ‘*’ token
I am always astonished about the bad quality of error messages when it comes to templates.. I mean.. "expected constructor, destructor, or type conversion"???
I don't want to start compiler-bashing or something, but mine is saying:
1>c:\users\imi\documents\visual studio 2010\projects\test\test\test.cpp(38): warning C4346: 'CRedBlackTree<T>::SNode' : dependent name is not a type
1> prefix with 'typename' to indicate a type
And imi, you're right. In fact, this is one of the reasons that i am somewhat pissed about C++. Whenever i try something new (no matter how trivial it seems), some ill-designed language feature comes by and destroys everything. For example, try to compile (and correct) the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class A;
class B;
class A
{
public:
// In the real world, this would rather be some sort of smart pointer
typedef A* ptr;
B::ptr m_pB;
};
class B
{
public:
typedef B* ptr;
A::ptr m_pA;
};
Is there any way to achieve a behavior like i intended with similar coding effort?
The compiler error sort of makes sense when you figure that the compiler is erroring because it doesn't know what to do. It doesn't recognize SNode as a typename because the rules of C++ say it shouldn't.
If it could recognize it as a typename, there'd be no need for the error.
But I agree that something like "SNode is an unrecognized identifier" would be more appropriate and would make more sense.
TheBear wrote:
Is there any way to achieve a behavior like i intended with similar coding effort?
AFAIK, no.
I have yet to find any way around that circular typedef issue.
An alternative is to make 'ptr' global typedefs instead of putting them in the class. Like typedef A* Aptr;. Then you have several options for getting around the above problem.
class B;
template<int>
class A_
{
public:
// In the real world, this would rather be some sort of smart pointer
typedef A_* ptr;
typename B::ptr m_pB;
};
typedef A_<0> A; // can use anything. Use "void" and template<class> if it looks better to you ;)
class B
{
public:
typedef B* ptr;
A::ptr m_pA;
};