By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,268 Members | 1,371 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,268 IT Pros & Developers. It's quick & easy.

Two-Phase lookup

P: n/a
Hi,

I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.

template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}

When compiled with g++ 4.0.2 gives the following error:

test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >)':
test.cc:31: error: expected `;' before 'iter'
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >) [with TYPE = char]':
test.cc:42: instantiated from here
test.cc:31: error: dependent-name
'std::map<int,TYPE,std::less<int>,std::allocator<s td::pair<const int,
TYPE >::iterator' is parsed as a non-type, but instantiation yields
a type
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant

Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.

According to this article:
http://www.codeproject.com/cpp/TwoPh...&select=949325

It should be dependant because its type is dependant. Which makes a
great deal of sense.

Given all that, what's causing this 'parsed as non-type' error?

This is purely an academic question, but its something I can't figure
out.

Thanks,
Paul Davis

Feb 8 '07 #1
Share this Question
Share on Google+
13 Replies


P: n/a
On 2/7/07 3:56 PM, in article
11*********************@v45g2000cwv.googlegroups.c om,
"pa***************@gmail.com" <pa***************@gmail.comwrote:
>
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.

template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}

When compiled with g++ 4.0.2 gives the following error:

test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
test.cc:31: error: expected `;' before 'iter'

Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.
The compiler performs "two phase" name-lookup within the definition of a
class template, a nested class of a class template, a member of a class
template, or a member of a nested class of a class template - but not within
a function template like foo() in the example above.

Greg

Feb 8 '07 #2

P: n/a
On 8 Feb., 03:33, Greg Herlihy <gre...@pacbell.netwrote:
On 2/7/07 3:56 PM, in article
1170892566.094977.95...@v45g2000cwv.googlegroups.c om,

"paul.joseph.da...@gmail.com" <paul.joseph.da...@gmail.comwrote:
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.
template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
When compiled with g++ 4.0.2 gives the following error:
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
test.cc:31: error: expected `;' before 'iter'
Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.

The compiler performs "two phase" name-lookup within the definition of a
class template, a nested class of a class template, a member of a class
template, or a member of a nested class of a class template - but not within
a function template like foo() in the example above.

Greg- Zitierten Text ausblenden -

- Zitierten Text anzeigen -
Greg Herlihy <gre...@pacbell.netwrote:
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
visual studi 2005 accepts your code,
for gcc add typename
e.g.:
typename std::map< int, TYPE >::iterator iter ;
lg Rudi

Feb 8 '07 #3

P: n/a
pa***************@gmail.com wrote:
Hi,

I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.

template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}

When compiled with g++ 4.0.2 gives the following error:

test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >)':
test.cc:31: error: expected `;' before 'iter'
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >) [with TYPE = char]':
test.cc:42: instantiated from here
test.cc:31: error: dependent-name
'std::map<int,TYPE,std::less<int>,std::allocator<s td::pair<const int,
TYPE >::iterator' is parsed as a non-type, but instantiation yields
a type
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant

Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.

According to this article:
http://www.codeproject.com/cpp/TwoPh...&select=949325

It should be dependant because its type is dependant. Which makes a
great deal of sense.

Given all that, what's causing this 'parsed as non-type' error?

This is purely an academic question, but its something I can't figure
out.

Thanks,
Paul Davis
IMHO, I do not think this is a symptom of Two-Phase Lookup. I think this
is how the C++ parser think something is but turns out not to be.
What do I mean about this probably best described by an example.

class A
{
public:
typedef int someType;
static int someVariable;
}

Now let us look at this code (without any context)

A::someType
A::someVariable

It seems to be quite clear that A::SomethingGoesHere could
either be a type or a variable (and even a function too!!)

So when the compiler first reads this part of the line:

std::map< int, TYPE >::iterator

The first thing, the parse assumes is "Hmmmmm
std::map<int,TYPE>::iterator must be a member variable!!"
(technically, it is a non-type: member variable or function)
which obviously is not. But natually, when the template gets
instantiated, it proves to be fatal!! what it originally assumed
was supposed to be a non-type is used as a type and in addition,
the instantiation process revealed it to be a type. OMG What
will Mr. Compiler do?!

So how do we correct this? Well actually, you compiler tells
you how to correct it!!
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant
This means, you should do this:
template<typename TYPE>
void
foo( std::map< int, TYPE &pmap )
{
typename std::map< int, TYPE >::iterator iter ;
}

BTW, I added a reference to your pmap input :)

I hope that helped. :)

Good Luck!
Feb 8 '07 #4

P: n/a
On Feb 8, 1:26 am, Piyo <cybermax...@yahoo.comwrote:
paul.joseph.da...@gmail.com wrote:
Hi,
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.
template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
When compiled with g++ 4.0.2 gives the following error:
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >)':
test.cc:31: error: expected `;' before 'iter'
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >) [with TYPE = char]':
test.cc:42: instantiated from here
test.cc:31: error: dependent-name
'std::map<int,TYPE,std::less<int>,std::allocator<s td::pair<const int,
TYPE >::iterator' is parsed as a non-type, but instantiation yields
a type
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant
Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.
According to this article:
http://www.codeproject.com/cpp/TwoPh...0&forumid=1154...
It should be dependant because its type is dependant. Which makes a
great deal of sense.
Given all that, what's causing this 'parsed as non-type' error?
This is purely an academic question, but its something I can't figure
out.
Thanks,
Paul Davis

IMHO, I do not think this is a symptom of Two-Phase Lookup. I think this
is how the C++ parser think something is but turns out not to be.
What do I mean about this probably best described by an example.

class A
{
public:
typedef int someType;
static int someVariable;

}

Now let us look at this code (without any context)

A::someType
A::someVariable

It seems to be quite clear that A::SomethingGoesHere could
either be a type or a variable (and even a function too!!)

So when the compiler first reads this part of the line:

std::map< int, TYPE >::iterator

The first thing, the parse assumes is "Hmmmmm
std::map<int,TYPE>::iterator must be a member variable!!"
(technically, it is a non-type: member variable or function)
which obviously is not. But natually, when the template gets
instantiated, it proves to be fatal!! what it originally assumed
was supposed to be a non-type is used as a type and in addition,
the instantiation process revealed it to be a type. OMG What
will Mr. Compiler do?!

So how do we correct this? Well actually, you compiler tells
you how to correct it!!
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant

This means, you should do this:
template<typename TYPE>
void
foo( std::map< int, TYPE &pmap )
{
typename std::map< int, TYPE >::iterator iter ;

}

BTW, I added a reference to your pmap input :)

I hope that helped. :)

Good Luck!
Hi,

The compiler message is pretty straightforward about adding typename
to get the compilation to work. The question here is what about the
language is making this happen.

I've just found some interesting stuff in Stroustrup's "The C++
Programming Language 3rd Ed." in sections C.13.5 and C.13.8
>From C.13.5 (page 857 first paragraph of text in my copy) I quote:
"Naturally, a compiler could postpone all checking until
instantiation time where all information is avialable and could then
accept such examples. Howerver, that would be a standard language
extension."

On the next page, Stroustrup says, "The resolution is simple: unless
otherwise stated, an identifier is assumed to refer to something that
is not a type or a template."

Here's another concrete example:

#include <iostream>
#include <map>

template<typename T1>
class A
{
public:
typedef T1 mem_type ;

T1 x ;
} ;

template<typename T2>
void
foo( T2& var )
{
bar( var.x ) ; //This call compiles because of two-phase
construction.
//var.x is type-dependant, thus, its lookup is
delayed
//until template instantiation.

T2::mem_type val ; //This line is *not* affected by two-phase
lookup.
//Why not?
}

void
bar( int x )
{
std::cerr << x << std::endl ;
}

int
main( int argc, char* argv[] )
{
A<inta ;
a.x = 1 ;
foo( a ) ;
}

Does this mean that two-phase lookup applies only to function calls
and not variable instantiations? Judging from the second quote from
Stroustrup and this example, I'm guessing this is the case.

Thanks,
Paul

Feb 8 '07 #5

P: n/a
On Feb 7, 8:33 pm, Greg Herlihy <gre...@pacbell.netwrote:
On 2/7/07 3:56 PM, in article
1170892566.094977.95...@v45g2000cwv.googlegroups.c om,

"paul.joseph.da...@gmail.com" <paul.joseph.da...@gmail.comwrote:
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.
template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
When compiled with g++ 4.0.2 gives the following error:
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
test.cc:31: error: expected `;' before 'iter'
Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.

The compiler performs "two phase" name-lookup within the definition of a
class template, a nested class of a class template, a member of a class
template, or a member of a nested class of a class template - but not within
a function template like foo() in the example above.

Greg
Greg,

This isn't quite correct. I've already posted an example that shows
otherwise. The question though is whether or not two-phase lookup
applies only to function calls vs. variable instantiations.

Paul

Feb 8 '07 #6

P: n/a
pa***************@gmail.com wrote:
On Feb 8, 1:26 am, Piyo <cybermax...@yahoo.comwrote:
>paul.joseph.da...@gmail.com wrote:
>>Hi,
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.
template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
When compiled with g++ 4.0.2 gives the following error:
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >)':
test.cc:31: error: expected `;' before 'iter'
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >) [with TYPE = char]':
test.cc:42: instantiated from here
test.cc:31: error: dependent-name
'std::map<int,TYPE,std::less<int>,std::allocator <std::pair<const int,
TYPE >::iterator' is parsed as a non-type, but instantiation yields
a type
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator< std::pair<const int,
TYPE >::iterator' if a type is meant
Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.
According to this article:
http://www.codeproject.com/cpp/TwoPh...0&forumid=1154...
It should be dependant because its type is dependant. Which makes a
great deal of sense.
Given all that, what's causing this 'parsed as non-type' error?
This is purely an academic question, but its something I can't figure
out.
Thanks,
Paul Davis
IMHO, I do not think this is a symptom of Two-Phase Lookup. I think this
is how the C++ parser think something is but turns out not to be.
What do I mean about this probably best described by an example.

class A
{
public:
typedef int someType;
static int someVariable;

}

Now let us look at this code (without any context)

A::someType
A::someVariable

It seems to be quite clear that A::SomethingGoesHere could
either be a type or a variable (and even a function too!!)

So when the compiler first reads this part of the line:

std::map< int, TYPE >::iterator

The first thing, the parse assumes is "Hmmmmm
std::map<int,TYPE>::iterator must be a member variable!!"
(technically, it is a non-type: member variable or function)
which obviously is not. But natually, when the template gets
instantiated, it proves to be fatal!! what it originally assumed
was supposed to be a non-type is used as a type and in addition,
the instantiation process revealed it to be a type. OMG What
will Mr. Compiler do?!

So how do we correct this? Well actually, you compiler tells
you how to correct it!!
> test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant

This means, you should do this:
template<typename TYPE>
void
foo( std::map< int, TYPE &pmap )
{
typename std::map< int, TYPE >::iterator iter ;

}

BTW, I added a reference to your pmap input :)

I hope that helped. :)

Good Luck!

Hi,

The compiler message is pretty straightforward about adding typename
to get the compilation to work. The question here is what about the
language is making this happen.

I've just found some interesting stuff in Stroustrup's "The C++
Programming Language 3rd Ed." in sections C.13.5 and C.13.8
>>From C.13.5 (page 857 first paragraph of text in my copy) I quote:
"Naturally, a compiler could postpone all checking until
instantiation time where all information is avialable and could then
accept such examples. Howerver, that would be a standard language
extension."

On the next page, Stroustrup says, "The resolution is simple: unless
otherwise stated, an identifier is assumed to refer to something that
is not a type or a template."

Here's another concrete example:

#include <iostream>
#include <map>

template<typename T1>
class A
{
public:
typedef T1 mem_type ;

T1 x ;
} ;

template<typename T2>
void
foo( T2& var )
{
bar( var.x ) ; //This call compiles because of two-phase
construction.
//var.x is type-dependant, thus, its lookup is
delayed
//until template instantiation.

T2::mem_type val ; //This line is *not* affected by two-phase
lookup.
//Why not?
}

void
bar( int x )
{
std::cerr << x << std::endl ;
}

int
main( int argc, char* argv[] )
{
A<inta ;
a.x = 1 ;
foo( a ) ;
}

Does this mean that two-phase lookup applies only to function calls
and not variable instantiations? Judging from the second quote from
Stroustrup and this example, I'm guessing this is the case.

Thanks,
Paul
Interesting point. I do think that both are dependent names and will
require a two-phase lookup to resolve what function (bar -bar(int)) or
type (T2::mem_type -int) should be used.

I will need to check my copy of Stroustrup's book to see in what context
he mentions this to figure out what to make of it. I believe that he is
saying that if a dependent name is first encountered (first pass) the
compiler will assume it is a non-type.

This means:

T2::mem_type at the first pass will be assumed to be a variable or a
function (aka non-type). On the other hand, bar() on the first pass is
correctly parsed as a function, we just don't know which one.

On the second pass, when all templates have been instantiated, it is
clear to the compiler that T2::mem_type is a type but the parse tree for
a type has already been generated and it flags it as an error (for GNU
and is probably "fixed on the fly" by Microsoft). bar() on the other
hand does some Koenig lookups and finds bar(int) satisfies the call.

BTW, you need to get into the habit of using typename in your examples
since, you bring up a valid question, does two-phase lookup occur on a
type but the compiler is complaining about a different thing: it is
confused as to whether or not the dependent name is a type or a
non-type. Which is why people reply to your post to simply add typename.

Hope that helps!
Feb 8 '07 #7

P: n/a
On Feb 8, 12:23 pm, Clint Chua <cybermax...@yahoo.comwrote:
paul.joseph.da...@gmail.com wrote:
On Feb 8, 1:26 am, Piyo <cybermax...@yahoo.comwrote:
paul.joseph.da...@gmail.com wrote:
Hi,
I've just had my first encounter with two-phase lookup and I'm
scratching my head a bit. The idea behind two phase look up is pretty
easy to understand, but I have a case that fails to compile although
it appears to me that it should.
template<typename TYPE>
void
foo( std::map< int, TYPE pmap )
{
std::map< int, TYPE >::iterator iter ;
}
When compiled with g++ 4.0.2 gives the following error:
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >)':
test.cc:31: error: expected `;' before 'iter'
test.cc: In function 'void foo(std::map<int, TYPE, std::less<int>,
std::allocator<std::pair<const int, TYPE >) [with TYPE = char]':
test.cc:42: instantiated from here
test.cc:31: error: dependent-name
'std::map<int,TYPE,std::less<int>,std::allocator< std::pair<const int,
TYPE >::iterator' is parsed as a non-type, but instantiation yields
a type
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<s td::pair<const int,
TYPE >::iterator' if a type is meant
Unless I'm mistaken, this should be a dependant name lookup, and thus
not be looked up until template instantiation.
According to this article:
http://www.codeproject.com/cpp/TwoPh...0&forumid=1154...
It should be dependant because its type is dependant. Which makes a
great deal of sense.
Given all that, what's causing this 'parsed as non-type' error?
This is purely an academic question, but its something I can't figure
out.
Thanks,
Paul Davis
IMHO, I do not think this is a symptom of Two-Phase Lookup. I think this
is how the C++ parser think something is but turns out not to be.
What do I mean about this probably best described by an example.
class A
{
public:
typedef int someType;
static int someVariable;
}
Now let us look at this code (without any context)
A::someType
A::someVariable
It seems to be quite clear that A::SomethingGoesHere could
either be a type or a variable (and even a function too!!)
So when the compiler first reads this part of the line:
std::map< int, TYPE >::iterator
The first thing, the parse assumes is "Hmmmmm
std::map<int,TYPE>::iterator must be a member variable!!"
(technically, it is a non-type: member variable or function)
which obviously is not. But natually, when the template gets
instantiated, it proves to be fatal!! what it originally assumed
was supposed to be a non-type is used as a type and in addition,
the instantiation process revealed it to be a type. OMG What
will Mr. Compiler do?!
So how do we correct this? Well actually, you compiler tells
you how to correct it!!
test.cc:31: note: say 'typename
std::map<int,TYPE,std::less<int>,std::allocator<st d::pair<const int,
TYPE >::iterator' if a type is meant
This means, you should do this:
template<typename TYPE>
void
foo( std::map< int, TYPE &pmap )
{
typename std::map< int, TYPE >::iterator iter ;
}
BTW, I added a reference to your pmap input :)
I hope that helped. :)
Good Luck!
Hi,
The compiler message is pretty straightforward about adding typename
to get the compilation to work. The question here is what about the
language is making this happen.
I've just found some interesting stuff in Stroustrup's "The C++
Programming Language 3rd Ed." in sections C.13.5 and C.13.8
>From C.13.5 (page 857 first paragraph of text in my copy) I quote:
"Naturally, a compiler could postpone all checking until
instantiation time where all information is avialable and could then
accept such examples. Howerver, that would be a standard language
extension."
On the next page, Stroustrup says, "The resolution is simple: unless
otherwise stated, an identifier is assumed to refer to something that
is not a type or a template."
Here's another concrete example:
#include <iostream>
#include <map>
template<typename T1>
class A
{
public:
typedef T1 mem_type ;
T1 x ;
} ;
template<typename T2>
void
foo( T2& var )
{
bar( var.x ) ; //This call compiles because of two-phase
construction.
//var.x is type-dependant, thus, its lookup is
delayed
//until template instantiation.
T2::mem_type val ; //This line is *not* affected by two-phase
lookup.
//Why not?
}
void
bar( int x )
{
std::cerr << x << std::endl ;
}
int
main( int argc, char* argv[] )
{
A<inta ;
a.x = 1 ;
foo( a ) ;
}
Does this mean that two-phase lookup applies only to function calls
and not variable instantiations? Judging from the second quote from
Stroustrup and this example, I'm guessing this is the case.
Thanks,
Paul

Interesting point. I do think that both are dependent names and will
require a two-phase lookup to resolve what function (bar -bar(int)) or
type (T2::mem_type -int) should be used.

I will need to check my copy of Stroustrup's book to see in what context
he mentions this to figure out what to make of it. I believe that he is
saying that if a dependent name is first encountered (first pass) the
compiler will assume it is a non-type.

This means:

T2::mem_type at the first pass will be assumed to be a variable or a
function (aka non-type). On the other hand, bar() on the first pass is
correctly parsed as a function, we just don't know which one.
I've added another example to show that this is how g++ 4.0.2 is in
fact working. Identifiers parsed are assumed to be a variable or
function until the second phase of lookup.
On the second pass, when all templates have been instantiated, it is
clear to the compiler that T2::mem_type is a type but the parse tree for
a type has already been generated and it flags it as an error (for GNU
and is probably "fixed on the fly" by Microsoft).
I read somewhere that Microsoft's VC6 is non-standards compliant in
this manner. Templates are not processed at all until the point of
instantiation. (Thus, no two-phase lookup.) VC7.1 also does this as an
extension that can be turned off. (/v or /i or /z can't recall atm)

bar() on the other
hand does some Koenig lookups and finds bar(int) satisfies the call.
Yes, according to stroustrup's book, bar() is resolved by normal
lookup at the point of instantiation, which includes koenig. Although,
koenig isn't invovled in this specific case.
BTW, you need to get into the habit of using typename in your examples
since, you bring up a valid question, does two-phase lookup occur on a
type but the compiler is complaining about a different thing: it is
confused as to whether or not the dependent name is a type or a
non-type. Which is why people reply to your post to simply add typename.
The point of the post was why adding typename worked. I found it
helpful to show the faulty code snippet rather than one that worked.
>
Hope that helps!
#include <iostream>
#include <map>

template<typename T1>
class A
{
public:
typedef T1 mem_type ;
} ;

template<typename T2>
void
foo( T2& var )
{
T2::mem_type( 3 ) ;
T2::mem_type = 4 ;
}

int
main( int argc, char* argv[] )
{
A<inta ;
a.x = 1 ;
foo( a ) ;
}

test.cc: In function 'void foo(T2&) [with T2 = A<int>]':
test.cc:32: instantiated from here
test.cc:17: error: dependent-name 'T2::mem_type' is parsed as a non-
type, but instantiation yields a type
test.cc:17: note: say 'typename T2::mem_type' if a type is meant
test.cc:18: error: dependent-name 'T2::mem_type' is parsed as a non-
type, but instantiation yields a type
test.cc:18: note: say 'typename T2::mem_type' if a type is meant

The point of this error-producing example is that both incorrect lines
are *not* flagged as errors until the second phase of lookup (template
instantiation). Therefore, the compiler (g++ at least) must be
assuming all encountered symbols are either function names or
variables and the typename identifies things as such and delays lookup
of the type until the second phase.

So, I now finally feel comfortable with that explanation. Although, I
would be interested to know what about the compiler implementation
prevents it from being able to determine the difference between
dependant and non-dependant typenames while being able to make this
determination for variables and functions.

Thanks,
Paul

Feb 8 '07 #8

P: n/a
On 8 Feb 2007 13:13:10 -0800, "pa***************@gmail.com"
<pa***************@gmail.comwrote:

>BTW, you need to get into the habit of using typename in your examples
since, you bring up a valid question, does two-phase lookup occur on a
type but the compiler is complaining about a different thing: it is
confused as to whether or not the dependent name is a type or a
non-type. Which is why people reply to your post to simply add typename.

The point of the post was why adding typename worked. I found it
helpful to show the faulty code snippet rather than one that worked.
This has nothing to do with two-phase name resolution.

Although the compiler is not obliged to resolve names until the point of use,
it is still obliged to check the _syntax_ of your template definition, and it
has no way to do this unless it can tell which names refer to types, and which
names refer to variables.

14.6(2):

"A name used in a template declaration or definition and that is dependent on
a template-parameter is assumed not to name a type unless the applicable name
lookup finds a type name or the name is qualified by the keyword typename."
Example:

template <typename T>
void fn0()
{
typename T::a* p; // a is treated as a type defined in the scope of T,
// and p is a pointer to it.
}

template <typename T>
void fn1()
{
T::a* p; // a is treated as a static variable of T,
// multiplied by p.
}

-dr
Feb 9 '07 #9

P: n/a
On Feb 9, 1:05 am, Dave Rahardja <a...@me.comwrote:
On 8 Feb 2007 13:13:10 -0800, "paul.joseph.da...@gmail.com"

<paul.joseph.da...@gmail.comwrote:
BTW, you need to get into the habit of using typename in your examples
since, you bring up a valid question, does two-phase lookup occur on a
type but the compiler is complaining about a different thing: it is
confused as to whether or not the dependent name is a type or a
non-type. Which is why people reply to your post to simply add typename.
The point of the post was why adding typename worked. I found it
helpful to show the faulty code snippet rather than one that worked.

This has nothing to do with two-phase name resolution.

Although the compiler is not obliged to resolve names until the point of use,
it is still obliged to check the _syntax_ of your template definition, and it
has no way to do this unless it can tell which names refer to types, and which
names refer to variables.
I don't have a copy of the standard, but as I read Stroustrup's book
the compiler *is* in fact obliged to resolve non-dependant names. And
further, what I've written is syntactically correct minus the
'typename' keyword. The question is 'Why is "typename" required?' I
understand its meaning is to tell the compiler that a given symbol is
a type vs. a variable. But the driving question is why is the compiler
able to tell in normal code yet not in template code?
14.6(2):

"A name used in a template declaration or definition and that is dependent on
a template-parameter is assumed not to name a type unless the applicable name
lookup finds a type name or the name is qualified by the keyword typename."
I haven't the slightest what this refers to. I'm assuming its the
standard. But this is *not* an answer to the underlying question of
why it is so. It is only a statment that it is so.
Example:

template <typename T>
void fn0()
{
typename T::a* p; // a is treated as a type defined in the scope of T,
// and p is a pointer to it.

}
Yep. If I tell the compiler something is a type, it believes me.
Again, why in this circumstance do I have to *tell* it specifically
that this is a type?

Why are we not writing code like:

typname int
main( typename int argc, typename char* argv[] )
{
typename int a = 4 ;
}
template <typename T>
void fn1()
{
T::a* p; // a is treated as a static variable of T,
// multiplied by p.

}

-dr
I believe this comment to be incoorect. T::a is not treated as a
static variable of T. This is a syntax error (According to Stroustrup
and g++ 4.0.2).

As far as I can tell, two-phase lookup is a method to delay looking up
symbols that it cannot define until a time when definition is
possible. This works for function calls and variable names as I have
shown. The question is, why not for types?

Stroustrup's line is something along the lines that "We cannot expect
compilers to be psychic." I haven't the slightest what this means,
because I've given an example that compiles a template referencing an
undefined symbol.

There has got to either be a theoretical or implementation reason for
this behavior. By theoretical, I mean there's an example that shows an
ambiguity when the compiler delays lookup of a type and implemenation
is more of a "this opens a can of worms best left closed" type of
answer (which is perfectly acceptable if it is indeed the answer).

That being said, I haven't been able to determine the reason for this
behavior. Only that this *is* the behavior.

Thanks,
Paul Davis

Feb 9 '07 #10

P: n/a
On 9 Feb 2007 02:54:38 -0800, "pa***************@gmail.com"
<pa***************@gmail.comwrote:
>I don't have a copy of the standard, but as I read Stroustrup's book
the compiler *is* in fact obliged to resolve non-dependant names. And
further, what I've written is syntactically correct minus the
'typename' keyword. The question is 'Why is "typename" required?' I
understand its meaning is to tell the compiler that a given symbol is
a type vs. a variable. But the driving question is why is the compiler
able to tell in normal code yet not in template code?
Correct, for _non_ dependent names. And for non-dependent names you do not
need the typename keyword.
>
>14.6(2):

"A name used in a template declaration or definition and that is dependent on
a template-parameter is assumed not to name a type unless the applicable name
lookup finds a type name or the name is qualified by the keyword typename."

I haven't the slightest what this refers to. I'm assuming its the
standard. But this is *not* an answer to the underlying question of
why it is so. It is only a statment that it is so.
Yes, this is from the standard.
>
>Example:

template <typename T>
void fn0()
{
typename T::a* p; // a is treated as a type defined in the scope of T,
// and p is a pointer to it.

}

Yep. If I tell the compiler something is a type, it believes me.
Again, why in this circumstance do I have to *tell* it specifically
that this is a type?

Why are we not writing code like:

typname int
main( typename int argc, typename char* argv[] )
{
typename int a = 4 ;
}
Because it is not necessary. Non-templated code by definition must have all of
the needed information where the code is encountered.
>
>template <typename T>
void fn1()
{
T::a* p; // a is treated as a static variable of T,
// multiplied by p.

}

-dr

I believe this comment to be incoorect. T::a is not treated as a
static variable of T. This is a syntax error (According to Stroustrup
and g++ 4.0.2).
It is a syntax error not because of typename, but because p is undeclared. The
standard specifically gives this behavior as an example.

Here's an example that compiles WITH or WITHOUT "typename":

int p;

template <typename T>
void fn()
{
typename T::a* p; // remove typename -- still compiles.
// With typename: means "p is a pointer to T::a".
// Without: means "multiply T::a by p, then discard
// the result".
}

struct A
{
static int a;
};

struct B
{
typedef int a;
};

int main()
{
fn<A>(); // Works only when typename is absent
fn<B>(); // Works only when typename is present
}

Try it out.

>As far as I can tell, two-phase lookup is a method to delay looking up
symbols that it cannot define until a time when definition is
possible. This works for function calls and variable names as I have
shown. The question is, why not for types?
The reason for requiring the compiler to determine whether a dependent name is
a _type_ or a _variable_ is that a confusion of the two behaviors yield two
different _semantics_ of the same statement, and prevents strong error
checking.

Remember that templates are not macros. They are strongly typed, and are
rigorously checked for syntax errors, even when the symbols they use are not
yet known. In order to do that, the compiler needs to know what each dependent
name is supposed to represent, even before it is bound to an actual symbol
during instantiation.

It turns out that automatically telling the difference between a dependent
type name and a dependent variable name is not possible at the point of
template definition. Thus the programmer must help the compiler by specifying
the typename keyword whenever a dependent name refers to a type.

>There has got to either be a theoretical or implementation reason for
this behavior. By theoretical, I mean there's an example that shows an
ambiguity when the compiler delays lookup of a type and implemenation
is more of a "this opens a can of worms best left closed" type of
answer (which is perfectly acceptable if it is indeed the answer).

That being said, I haven't been able to determine the reason for this
behavior. Only that this *is* the behavior.
The reason is that letting templates have this sort of semantic ambiguity is a
Bad Thing.

-dr
Feb 9 '07 #11

P: n/a
* Dave Rahardja:
>
int p;

template <typename T>
void fn()
{
typename T::a* p; // remove typename -- still compiles.
// With typename: means "p is a pointer to T::a".
// Without: means "multiply T::a by p, then discard
// the result".
}

struct A
{
static int a;
};

struct B
{
typedef int a;
};

int main()
{
fn<A>(); // Works only when typename is absent
fn<B>(); // Works only when typename is present
}

Try it out.
This is a beautiful example.

If we had a collection of clc++ "pearls", I'd have submitted this.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 9 '07 #12

P: n/a
On Feb 9, 8:51 am, Dave Rahardja <a...@me.comwrote:
On 9 Feb 2007 02:54:38 -0800, "paul.joseph.da...@gmail.com"

<paul.joseph.da...@gmail.comwrote:
I don't have a copy of the standard, but as I read Stroustrup's book
the compiler *is* in fact obliged to resolve non-dependant names. And
further, what I've written is syntactically correct minus the
'typename' keyword. The question is 'Why is "typename" required?' I
understand its meaning is to tell the compiler that a given symbol is
a type vs. a variable. But the driving question is why is the compiler
able to tell in normal code yet not in template code?

Correct, for _non_ dependent names. And for non-dependent names you do not
need the typename keyword.
14.6(2):
"A name used in a template declaration or definition and that is dependent on
a template-parameter is assumed not to name a type unless the applicable name
lookup finds a type name or the name is qualified by the keyword typename."
I haven't the slightest what this refers to. I'm assuming its the
standard. But this is *not* an answer to the underlying question of
why it is so. It is only a statment that it is so.

Yes, this is from the standard.


Example:
template <typename T>
void fn0()
{
typename T::a* p; // a is treated as a type defined in the scope of T,
// and p is a pointer to it.
}
Yep. If I tell the compiler something is a type, it believes me.
Again, why in this circumstance do I have to *tell* it specifically
that this is a type?
Why are we not writing code like:
typname int
main( typename int argc, typename char* argv[] )
{
typename int a = 4 ;
}

Because it is not necessary. Non-templated code by definition must have all of
the needed information where the code is encountered.
template <typename T>
void fn1()
{
T::a* p; // a is treated as a static variable of T,
// multiplied by p.
}
-dr
I believe this comment to be incoorect. T::a is not treated as a
static variable of T. This is a syntax error (According to Stroustrup
and g++ 4.0.2).

It is a syntax error not because of typename, but because p is undeclared. The
standard specifically gives this behavior as an example.

Here's an example that compiles WITH or WITHOUT "typename":

int p;

template <typename T>
void fn()
{
typename T::a* p; // remove typename -- still compiles.
// With typename: means "p is a pointer to T::a".
// Without: means "multiply T::a by p, then discard
// the result".

}

struct A
{
static int a;

};

struct B
{
typedef int a;

};

int main()
{
fn<A>(); // Works only when typename is absent
fn<B>(); // Works only when typename is present

}
Touche about p not being defined.

This is example is precisely what I was looking for. Leaving this
lookup until the point of instantiation would generate to functions
with different behavior, which I can agree is Bad C++.
Try it out.
As far as I can tell, two-phase lookup is a method to delay looking up
symbols that it cannot define until a time when definition is
possible. This works for function calls and variable names as I have
shown. The question is, why not for types?

The reason for requiring the compiler to determine whether a dependent name is
a _type_ or a _variable_ is that a confusion of the two behaviors yield two
different _semantics_ of the same statement, and prevents strong error
checking.

Remember that templates are not macros. They are strongly typed, and are
rigorously checked for syntax errors, even when the symbols they use are not
yet known. In order to do that, the compiler needs to know what each dependent
name is supposed to represent, even before it is bound to an actual symbol
during instantiation.

It turns out that automatically telling the difference between a dependent
type name and a dependent variable name is not possible at the point of
template definition. Thus the programmer must help the compiler by specifying
the typename keyword whenever a dependent name refers to a type.
There has got to either be a theoretical or implementation reason for
this behavior. By theoretical, I mean there's an example that shows an
ambiguity when the compiler delays lookup of a type and implemenation
is more of a "this opens a can of worms best left closed" type of
answer (which is perfectly acceptable if it is indeed the answer).
That being said, I haven't been able to determine the reason for this
behavior. Only that this *is* the behavior.

The reason is that letting templates have this sort of semantic ambiguity is a
Bad Thing.

-dr
Thank you for all your help,
Paul Davis

Feb 9 '07 #13

P: n/a
On Fri, 09 Feb 2007 16:02:13 +0100, "Alf P. Steinbach" <al***@start.nowrote:
>* Dave Rahardja:
>>
int p;

template <typename T>
void fn()
{
typename T::a* p; // remove typename -- still compiles.
// With typename: means "p is a pointer to T::a".
// Without: means "multiply T::a by p, then discard
// the result".
}

struct A
{
static int a;
};

struct B
{
typedef int a;
};

int main()
{
fn<A>(); // Works only when typename is absent
fn<B>(); // Works only when typename is present
}

Try it out.

This is a beautiful example.

If we had a collection of clc++ "pearls", I'd have submitted this.
Thank you.

-dr
Feb 10 '07 #14

This discussion thread is closed

Replies have been disabled for this discussion.