syntax error in std::vector<T>::const_iterator where T = (class) U<V>

M

m0shbear

With the following code, I get the following error from my compiler:
"In member function 'void B<U>::C()': error: expected ';' before 'x'".
Which subtlety of using templates am I not aware of?

#include <vector>
template <class T> struct A {};
template <class U> struct B {
void C() { std::vector<A<U> >::const_iterator x;}
};
int main(){}
 
B

Bo Persson

m0shbear said:
With the following code, I get the following error from my compiler:
"In member function 'void B<U>::C()': error: expected ';' before
'x'". Which subtlety of using templates am I not aware of?

#include <vector>
template <class T> struct A {};
template <class U> struct B {
void C() { std::vector<A<U> >::const_iterator x;}
};
int main(){}

That the compiler cannot formally know that
std::vector<A<U>>::const_iterator is a type (because someone could
specialize std::vector for some user defined types). You have to add a
'typename' to specify what it is:

void C() { typename std::vector<A<U> >::const_iterator x;}


Bo Persson
 
M

m0shbear

That the compiler cannot formally know that
std::vector<A<U>>::const_iterator is a type (because someone could
specialize std::vector for some user defined types). You have to add a
'typename' to specify what it is:

 void C() { typename std::vector<A<U> >::const_iterator x;}

Bo Persson

Ah, now I understand the point of typename for disambiguating types. I
need to start reading TC++PL more religiously. In its listing of
vector, it had "typedef _typename_ ..." for a reason. And now I
understand what it is.

I'm curious as to why it's not in the C++ FAQ yet.
 
J

Juha Nieminen

Bo Persson said:
That the compiler cannot formally know that
std::vector<A<U>>::const_iterator is a type (because someone could
specialize std::vector for some user defined types). You have to add a
'typename' to specify what it is:

Is there any conrete example where the same dependent name could be
used as both a type name and a non-type name, and this could potentially
cause confusion? Why exactly is the 'typename' keyword necessary?
 
J

Johannes Schaub (litb)

m0shbear said:
With the following code, I get the following error from my compiler:
"In member function 'void B<U>::C()': error: expected ';' before 'x'".
Which subtlety of using templates am I not aware of?

#include <vector>
template <class T> struct A {};
template <class U> struct B {
void C() { std::vector<A<U> >::const_iterator x;}
};
int main(){}

For the typename FAQ see http://stackoverflow.com/questions/610245/where-to-
put-the-template-and-typename-on-dependent-names
 
B

Bo Persson

Juha said:
Is there any conrete example where the same dependent name could be
used as both a type name and a non-type name, and this could
potentially cause confusion? Why exactly is the 'typename' keyword
necessary?

Yes, if you specialize a class there is no requirements that the base
template and the specialization should have anything in common (except
their names :).


template<class T>
class vec
{
public:
class const_iterator
{
public:
// some members here
};
};

template<>
class vec<int>
{
public:
double const_iterator; // silly, but possible
};


Now, what is vec<T>::const_iterator, a type or a member variable?
Depends on what T is!


Bo Persson
 
J

James Kanze

Is there any conrete example where the same dependent name could be
used as both a type name and a non-type name, and this could potentially
cause confusion? Why exactly is the 'typename' keyword necessary?

extern int p;
template<typename T>
struct S : B<T>
{
B<T>::x * p; // marked statement
};

If B<T>::x is the name of a type, the marked statement is a
declaration of a pointer to that type. If it is the name of a
constant or a variable, the marked statement is an expression
statement, and the * is multiplication.

In a lot of cases, context would allow the compiler to make it
clear: only a type is legal, or a type is not legal, but the
committee decided to not require the compiler to take any
context into consideration.
 
J

Juha Nieminen

Bo Persson said:
Yes, if you specialize a class there is no requirements that the base
template and the specialization should have anything in common (except
their names :).

In your example if you try to use the specialization in code where
'const_iterator' is expected to be a type, you get a syntax error. In
the exact same way as if that 'typename' keyword had been specified.
So what's the difference?

That's not what I asked. I asked if there's a situation where you *don't*
get a syntax error, but it compiles fine but causes unwanted behavior.
 
J

Juha Nieminen

James Kanze said:
In a lot of cases, context would allow the compiler to make it
clear: only a type is legal, or a type is not legal, but the
committee decided to not require the compiler to take any
context into consideration.

The following doesn't compile. Why shouldn't it? I see no rational
reason why the compiler should refuse to compile it.

//---------------------------------------------------------------
#include <iostream>

template<typename T>
void foo()
{
T::f(); // Is 'f' a function or a type?
}

struct A
{
// 'f' is a function
static void f() { std::cout << "A\n"; }
};

struct B
{
// 'f' is a type
struct f
{
f() { std::cout << "B\n"; }
};
};

int main()
{
foo<A>();
foo<B>(); // Fails because B::f is a type
}
//---------------------------------------------------------------
 
P

Paul

Juha Nieminen said:
The following doesn't compile. Why shouldn't it? I see no rational
reason why the compiler should refuse to compile it.

//---------------------------------------------------------------
#include <iostream>

template<typename T>
void foo()
{
T::f(); // Is 'f' a function or a type?
}

struct A
{
// 'f' is a function
static void f() { std::cout << "A\n"; }
};

struct B
{
// 'f' is a type
struct f
{
f() { std::cout << "B\n"; }

Where is this function declared?
 
J

James Kanze

The following doesn't compile. Why shouldn't it? I see no rational
reason why the compiler should refuse to compile it.

Because the standard says that it shouldn't compile:). You've
presented an interesting question, however...
//---------------------------------------------------------------
#include <iostream>

template<typename T>
void foo()
{
T::f(); // Is 'f' a function or a type?

What's interesting here is that the syntax is remarkably similar
in both cases. Formally, if f is a function, this line is
a function call; if it's a type, the line is an "explicit type
conversion (funtional notation)". But unlike a lot of the other
cases, it's easy to imagine an implementation which doesn't
really distinguish between the two until far later. The choice,
here, can't have any impact on later code.

Still, the standard says that when parsing the template, the
compiler is required to assume that f is not a type.
struct A
{
// 'f' is a function
static void f() { std::cout << "A\n"; }
};
struct B
{
// 'f' is a type
struct f
{
f() { std::cout << "B\n"; }
};
};
int main()
{
foo<A>();
foo<B>(); // Fails because B::f is a type}
//---------------------------------------------------------------

That's what the standard requires.

I don't see why the compiler couldn't defer the decision in this
case; I suppose that the only reason it doesn't is to be
orthogonal with cases where it must know.
 
P

Paul

James Kanze said:
Because the standard says that it shouldn't compile:). You've
presented an interesting question, however...


What's interesting here is that the syntax is remarkably similar
in both cases. Formally, if f is a function, this line is
a function call; if it's a type, the line is an "explicit type
conversion (funtional notation)". But unlike a lot of the other
cases, it's easy to imagine an implementation which doesn't
really distinguish between the two until far later. The choice,
here, can't have any impact on later code.

Still, the standard says that when parsing the template, the
compiler is required to assume that f is not a type.





That's what the standard requires.

I don't see why the compiler couldn't defer the decision in this
case; I suppose that the only reason it doesn't is to be
orthogonal with cases where it must know.

--

This doesn't happen on my compiler. MS 32-bit optimising compiler version
14.00......
Here is my source code:

#include <iostream>
struct A{static void bar(){std::cout<<"A function.";}
};
struct B{
struct bar{ bar(){std::cout<<"In constructor.";} };
};

template<typename T>void foo() { T::bar();}

int main(){
foo<B>();
foo<A>();
}

// Output = In constructor.A function.
 
R

Robert Hairgrove

The following doesn't compile. Why shouldn't it? I see no rational
reason why the compiler should refuse to compile it.

//---------------------------------------------------------------
#include<iostream>

template<typename T>
void foo()
{
T::f(); // Is 'f' a function or a type?
}

If T::f(); were a function, it would have to return something (either
void, or a pointer, reference or object of some type). Since the class
name is "foo", it can't be parsed as a constructor. So it shouldn't
compile in any case, even lacking the "typename" keyword.

If you had written "T::foo();" instead, no typename would be needed
since this would obviously be the declaration of a class constructor (at
least I don't think it could be interpreted any other way).
 
R

Robert Hairgrove

If T::f(); were a function, it would have to return something (either
void, or a pointer, reference or object of some type). Since the class
name is "foo", it can't be parsed as a constructor. So it shouldn't
compile in any case, even lacking the "typename" keyword.

Oops ... I overlooked the fact that this is a function template, not a
class template.

So the compiler should look for a member function of T called f()
returning void. 'f' could not be a type (nor could T::f).
 
B

Bo Persson

Juha said:
In your example if you try to use the specialization in code where
'const_iterator' is expected to be a type, you get a syntax error.
In
the exact same way as if that 'typename' keyword had been specified.
So what's the difference?

The difference is that the compiler should be allowed to diagnose
template code before it is instantiated. If you don't know whether a
name is a type or not, a lot of code turns out to be impossible to
interpret. For example, is "a * b" a pointer declaration or a
multiplication? If I use b later on in the class, am I then using this
pointer or some b from an outer scope?
That's not what I asked. I asked if there's a situation where you
*don't* get a syntax error, but it compiles fine but causes
unwanted behavior.

It isn't allowed to do that. A name must either be a type or not. If
the compiler can't tell, it must assume that it is not.


Bo Persson
 
J

James Kanze

"James Kanze" <[email protected]> wrote in message

[...]
This doesn't happen on my compiler. MS 32-bit optimising compiler version
14.00......

Not all compilers are up to date concerning this. A lot
(included VC++ through 2005, at least) continue to defer all
template parsing until instantiation, at which point in time,
the meaning of f is unambiguously known. Implementing the
latest rules for name lookup in templates (aka breaking existing
code) isn't always the highest priority of compiler writers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top