Use of private nested types as return value of private methods.

Hi,

i am trying to write a container, namely a red black tree, but i can't figure one compiler error out. Here is my situation:

Header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef REDBLACKTREE_H_
#define REDBLACKTREE_H_

template <typename T>
class CRedBlackTree
{
	struct SNode;

public:
        // some public methods, everything works so far

private:

	struct SNode
	{
		bool	color;
		SNode* 	left;
		SNode* 	right;
		SNode* 	father;
		T* 		data;
	};
        
        // some private members

	SNode* find(const T* element) const;

	static SNode* m_spNil;
	static SNode* createNil();
};

// include the cpp here, so linking works;
// The .cpp file is excluded from build.
#include "RedBlackTree.cpp"

#endif /* REDBLACKTREE_H_ */ 


Here are the relevant parts of the cpp file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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

Why is that? And how to prevent this?

Greetings,
TheBear
It doesn't know SNode is a type name. Give it a hint by saying typename.

IE:

1
2
3
4
5
6
7
8
9
template <typename T>
typename CRedBlackTree<T>::SNode* CRedBlackTree<T>::m_spNil = CRedBlackTree<T>::createNil();

// and its initializer
template <typename T>
typename CRedBlackTree<T>::SNode*
CRedBlackTree<T>::createNil()
{
  //... 
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


as first line in output. Much better, IMHO..

Ciao, Imi
Last edited on
Thanks for the solution.

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.
Is there any way to achieve a behavior like i intended with similar coding effort?


Yes, but you will hate it. ;-)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
};


Ciao, Imi.
Ah, that's interesting @ imi.

I hadn't thought of that.

But yeah, ew.
Thanks to both of you.
Topic archived. No new replies allowed.