Template name lookup

J

jacob navia

Suppose a template like this:

template <typename T> class Index : public DataNode<T>
{
// Many lines of code later
static void Insert(UpdateBlock* ub)
{
if (GlobalVar) {
}
}
}

Many lines later
extern int GlobalVar;

No instantiations of the template are done before the declaration
of "GlobalVar"

This code is compiling with
o gcc
o msvc
o solaris sparc sun compiler
o IBM AIX xlc version 8.

BUT

With version 9 of the IBM compiler this doesn't work any more since the
compiler tell us that "GlobalVar" is not declared at template definition
time.

Who is correct?

All other compilers or IBM xlc version 9?

Thanks in advance for your help
 
V

Victor Bazarov

jacob said:
Suppose a template like this:

template <typename T> class Index : public DataNode<T>
{
// Many lines of code later
static void Insert(UpdateBlock* ub)
{
if (GlobalVar) {
}
}
}

Many lines later
extern int GlobalVar;

No instantiations of the template are done before the declaration
of "GlobalVar"

This code is compiling with
o gcc
o msvc
o solaris sparc sun compiler
o IBM AIX xlc version 8.

BUT

With version 9 of the IBM compiler this doesn't work any more since
the compiler tell us that "GlobalVar" is not declared at template
definition time.

Who is correct?

All other compilers or IBM xlc version 9?

The 'GlobarVar' is supposed to be visible at the point of first use
(in the template definition), see [temp.res]/9.

That means that gcc, msvc, solaris, xlc v8, are all wrong if they
accept the code as is.

V
 
J

jacob navia

Victor said:
jacob said:
Suppose a template like this:

template <typename T> class Index : public DataNode<T>
{
// Many lines of code later
static void Insert(UpdateBlock* ub)
{
if (GlobalVar) {
}
}
}

Many lines later
extern int GlobalVar;

No instantiations of the template are done before the declaration
of "GlobalVar"

This code is compiling with
o gcc
o msvc
o solaris sparc sun compiler
o IBM AIX xlc version 8.

BUT

With version 9 of the IBM compiler this doesn't work any more since
the compiler tell us that "GlobalVar" is not declared at template
definition time.

Who is correct?

All other compilers or IBM xlc version 9?

The 'GlobarVar' is supposed to be visible at the point of first use
(in the template definition), see [temp.res]/9.

Thanks for your quick answer. Maybe can you explain what
[temp.res]/9 means? (I am new here)
That means that gcc, msvc, solaris, xlc v8, are all wrong if they
accept the code as is.

Well... thanks but this is just incredible.
 
V

Victor Bazarov

jacob said:
Victor said:
jacob said:
Suppose a template like this:

template <typename T> class Index : public DataNode<T>
{
// Many lines of code later
static void Insert(UpdateBlock* ub)
{
if (GlobalVar) {
}
}
}

Many lines later
extern int GlobalVar;

No instantiations of the template are done before the declaration
of "GlobalVar"

This code is compiling with
o gcc
o msvc
o solaris sparc sun compiler
o IBM AIX xlc version 8.

BUT

With version 9 of the IBM compiler this doesn't work any more since
the compiler tell us that "GlobalVar" is not declared at template
definition time.

Who is correct?

All other compilers or IBM xlc version 9?

The 'GlobarVar' is supposed to be visible at the point of first use
(in the template definition), see [temp.res]/9.

Thanks for your quick answer. Maybe can you explain what
[temp.res]/9 means? (I am new here)

It is a reference to a paragraph in the Standard. [temp.res] is the
subclause, 9 is the paragraph number. If you need to look it up,
open the Standard, find "[temp.res]", scroll down to the 9th para.
Well... thanks but this is just incredible.

Not really. Name lookup rules are sometimes quite strict and the
compiler vendors feel like they are doing us a favour if they let
us write code like that. You might want to try your compilers
with this:

template<class T> struct B {};
template<class T> struct A : B<T>
{
static int foo() { return GlobalVar; } // line 4
};

extern int GlobalVar;

int main() {
return A<char>::foo();
}

If they compile this, they are in violation of the rule set forth
in Standard, [temp.res]/9. I tried it with Comeau online, it did
not compile it ('GlobalVar' is undefined on line 4). VC++ 2005
compiled it. VC++ 2008 EE compiled it.

V
 
A

Andrey Tarasevich

jacob said:
...
This code is compiling with
o gcc
o msvc
o solaris sparc sun compiler
o IBM AIX xlc version 8.
...

According to the rules of two-phase name lookup in template definitions,
this code is ill-formed. Non-dependent names (like 'GlobalVar' in your
case) are supposed to be looked up early.

I'm not surprised it compiles in MSVC, since it is a well-known and
documented non-compliance issue in that compiler, which still persists
in VS2005 (I son't know about VS2008). At the same time, my version of
GCC (3.4.4) correctly refuses to compile the code. Same for Comeau
online compiler.
 
J

jacob navia

Andrey said:
According to the rules of two-phase name lookup in template definitions,
this code is ill-formed. Non-dependent names (like 'GlobalVar' in your
case) are supposed to be looked up early.

I'm not surprised it compiles in MSVC, since it is a well-known and
documented non-compliance issue in that compiler, which still persists
in VS2005 (I son't know about VS2008). At the same time, my version of
GCC (3.4.4) correctly refuses to compile the code. Same for Comeau
online compiler.

We are using gcc 3.3.xx. That compiler compiles the above code
 
J

James Kanze

The 'GlobarVar' is supposed to be visible at the point of first use
(in the template definition), see [temp.res]/9.
That means that gcc, msvc, solaris, xlc v8, are all wrong if
they accept the code as is.

Not so much wrong as out of date. (Recent versions of g++ don't
accept this code. I'm not sure about the exact version number
where they made the change, but 3.1 accepted it, and 4.1
doesn't.)

Also, of course, many compilers will continue to accept it,
possibly under the control of a compiler option, in order to
avoid breaking existing code. I wouldn't be surprised if there
wasn't an option for VC++ 8 which would cause it to break, for
example. (Sun CC, or at least the versions I have access to,
*is* very out of date with regards to templates. VC++
pre-version 8 was as well, and I suspect that even version 8 has
options, probably activated by default, if I know MS, to support
existing code.)
 
J

James Kanze

jacob navia wrote:

[...]
Name lookup rules are sometimes quite strict and the compiler
vendors feel like they are doing us a favour if they let us
write code like that.

More importantly, name lookup rules changed with regards to
previously existing practice, and most compiler vendors feel
like they are doing you a favor not breaking existing code.
(I'm pretty sure that EDG has an option to allow this to
compile, even today, and you don't get any more standard
compliant than they.)

FWIW: strictly speaking, name lookup rules didn't change,
because there weren't any templates in C++ before the committee
added them. In practice, the issue is rather cloudy with
regards to who did what: the original CFront implementation of
templates (around 1990) didn't use two phase lookup. The
original CFront implementation of templates was also considered,
by it's authors, as very experimental (i.e. subject to change).
As early as 1992 or 1993, I think, it was clear that the final
standard would have something along the lines of two phase
lookup. Still, many compiler vendors implemented templates more
or less as "extended macros", without any warning to their
customers that this feature was unstable, even in its
definition, and shouldn't be used in production code. And to be
fair, given the alternatives (e.g. <generic.h>), most
programmers would have jumped on the possibility of using these
templates even had they known just how much they were likely to
change. Finally, it took longer than expected to finalize the
standard, and even longer for compilers to begin to be
conformant, so we end up with a large body of code which is,
according to the standard, broken. Compiler vendors (correctly,
IMNO) want to make life as easy as possible for their existing
customers, so they avoid breaking working code whenever
possible, even if it means non-conformance.
You might want to try your compilers
with this:
template<class T> struct B {};
template<class T> struct A : B<T>
{
static int foo() { return GlobalVar; } // line 4
};
extern int GlobalVar;
int main() {
return A<char>::foo();
}
If they compile this, they are in violation of the rule set forth
in Standard, [temp.res]/9. I tried it with Comeau online, it did
not compile it ('GlobalVar' is undefined on line 4). VC++ 2005
compiled it. VC++ 2008 EE compiled it.

In all three cases, with what options? From a quality of
implementation point of view, any modern compiler should be able
to work both ways: rejecting it in new code, but accepting in
legacy code. And of course, the only way the compiler knows
what code is new, and what is legacy, is that you tell it, by
means of an option. (Given the goals of the Comeau on line
compiler, Greg may not have activated this option in the EDG
front-end. Using it there wouldn't make sense. But I'm sure
it's there in the front-end, and I would hope that he's provided
an option to activate it in the versions he sells.)
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top