std::map in template class -> Ok in MSVC but not with G++

Hi everyone,

I have a problem with a template class and std::map. It seems to work fine on a friend computer using MSVC but it doesn't work on my computr using g++ (gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9) ). We searched why it doesn't work for a couple of days and we don't find why. I made a minimal code that reproduce the problem:
1
2
3
4
5
6
7
8
9
10
11
12
template< class A, class B>
class C{
	public:
		typedef std::map<A, B> Test;
		
		Test m_Map;
		
		B SomeFunction(){
			Test::iterator it = m_Map.begin();
			return (*it);
		};
};


It works well if we change std::map<A,B> to something like std::map<int, int> (anything but template parameters in fact)

The error is this one:
1
2
3
template.cpp: In member function ‘B C<A, B>::SomeFunction()’:
template.cpp:12: error: expected ‘;’ before ‘it’
template.cpp:13: error: ‘it’ was not declared in this scope


Any idea?

Thanks
Last edited on
add typename before Test::iterator you must tell the compiler that it's a type
Bazzy wrote:
add typename before Test::iterator you must


From the Forum summary page, it sounded like you were channeling Yoda. :-)
bwahahahahahahahah
LOL
It worked, thanks!
I am a bit curious why the typename is needed in this case. Is there a "typename" missing in the gcc typedef of std::map<>::iterator when it references its template arguments?
It's declaring something of type "std::map<A, B>::iterator", but since A and B are templates themselves, the compiler can't resolve std::map<A, B> at compile-time. So you need the typename keyword to tell it that it will resolve to a type.
It's declaring something of type "std::map<A, B>::iterator"


Butbutbut... if the iterator is defined within map like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
template<class K, class V>
struct map
{
    typedef typename pair<K,V> iterator;
};

template<class A, class B>
struct C
{
    typedef map<A,B> Test;
    Test::iterator it;
};
typedef map


shouldn't it work out of the box without the need of the "outer typename"? That's what I mean by "missing typename".

In my example, "it" is declared as typename map<A,B>::iterator which is typename pair<A,B> which makes the type clear again.

Ciao, Imi.

PS: My knowledge of this stuff is pretty outdated and blurry, though. I may be totally off the point here. Still, it seems strange to have to use typename in a simple map iterator declaration without anything else involved ;)

PPS:
but since A and B are templates themselves
They are?
Last edited on
Since the compiler doesn't know what map<A,B>::iterator is ( as map may be specialized to have a type called iterator with some types or a function called iterator with some other )
You must tell it that iterator is surely a type, thus you need typename
Ah.. I understand.. so this isn't about the STL implementation that comes with GCC vs. VC, but the compiler himself?

Let me construct something and explain it using my own words, to test whether I got the point. ;).

I made some simplification (and tested it with VC and gcc to get a grasp on who's right here):

1
2
3
4
5
6
// compiles in VC, doesn't compile in gcc
template<class X>
struct Foo { typedef int foo; };

template<class Y>
struct Bar { void bar() { Foo<Y>::foo x; } };


Since the template is never instantiated, it must only be checked for malformed syntax. As you said, the problem is with the syntax, as Foo<Y>::foo could be a function and then bar() is completely ill-formed.

gcc does this syntax checking of unused templates, whereas VC seem to not do it. If you actually use Bar somewhere, you get an error in VC as expected:

1
2
3
4
5
6
7
8
9
10
11
// doesn't compile anywhere
template<class X>
struct Foo { typedef int foo; };

template<>
struct Foo<int> { void foo(){} };

template<class Y>
struct Bar { void bar(){ Foo<Y>::foo x; } };

int main() { Bar<int>().bar(); }


Bad Microsoft! No dinner today! ;)


I still like VC's attitude more. :-D


Thanks for dragging me along, Bazzy.

Ciao, Imi.

Edit: Yikes! Seems like VC does practically no checking of any template-function if the template is not intantiated.. template<class T> struct A { void a() { -.!""& Moo! } }; compiles just fine. :-O
Last edited on
To be clear, the ambiguity of

map<A,B>::iterator

is between that being a type and iterator being a static variable declared inside map.
Topic archived. No new replies allowed.