Template name lookup

P

philchen1978

Hi,

I can compile the code below with GCC 3.4.2, because function g is a
"dependent name".

template<class T>
void f1(T t)
{
g(t);
}

void g(int i)
{

}

int main()
{
f1<int>(10);
return 0;
}

But if I change the function g to a template function, things became
different. I cannot pass the compilation with GCC 3.4.2, but it works
fine with Visual C/C++ 7.

template<class T>
void f1(T t)
{
g<0>(t);
}

template<int I>
void g(int i)
{

}

int main()
{
f1<int>(10);
return 0;
}

The error message from GCC is:
main.cpp: In function `void f1(T)':
main.cpp:23: error: `g' undeclared (first use this function)
main.cpp:23: error: (Each undeclared identifier is reported only once
for each function it appears in.)
main.cpp: At global scope:
main.cpp:28: error: `template<int I> void g(int)' used prior to
declaration

Why?

Thanks,

Phil
 
I

Ioannis Vranos

But if I change the function g to a template function, things became
different. I cannot pass the compilation with GCC 3.4.2, but it works
fine with Visual C/C++ 7.

template<class T>
void f1(T t)
{
g<0>(t);
}

template<int I>
void g(int i)
{

}

int main()
{
f1<int>(10);
return 0;
}

The error message from GCC is:
main.cpp: In function `void f1(T)':
main.cpp:23: error: `g' undeclared (first use this function)
main.cpp:23: error: (Each undeclared identifier is reported only once
for each function it appears in.)
main.cpp: At global scope:
main.cpp:28: error: `template<int I> void g(int)' used prior to
declaration

Why?


template<int I>
void g(int i)
{

}


template<class T>
void f1(T t)
{
g<0>(t);
}


int main()
{
f1<int>(10);
return 0;
}
 
C

Chris Theis

Hi,

I can compile the code below with GCC 3.4.2, because function g is a
"dependent name".

template<class T>
void f1(T t)
{
g(t);
}

void g(int i)
{

}

int main()
{
f1<int>(10);
return 0;
}

But if I change the function g to a template function, things became
different. I cannot pass the compilation with GCC 3.4.2, but it works
fine with Visual C/C++ 7.

template<class T>
void f1(T t)
{
g<0>(t);
}

template<int I>
void g(int i)
{

}

int main()
{
f1<int>(10);
return 0;
}

The error message from GCC is:
main.cpp: In function `void f1(T)':
main.cpp:23: error: `g' undeclared (first use this function)
main.cpp:23: error: (Each undeclared identifier is reported only once
for each function it appears in.)
main.cpp: At global scope:
main.cpp:28: error: `template<int I> void g(int)' used prior to
declaration

Why?

A first glance at your code suggested a problem with the GCC´s template
instantiation model. The problem is that connected to the point of
instantiation and the order that templates are substituted. For a more
detailed description I´d suggest for example "C++ templates" by David
Vandevoorde & Nicolai Josuttis.

Anyway, you can help yourself easily by putting the definition of g() before
f().

Cheers
Chris
 
V

vandevoorde

Chris said:
A first glance at your code suggested a problem with the GCC´s template
instantiation model.

I assume you meant "Visual C++" instead of "GCC" here?
GNU is correct in refusing the code (Visual C++ does not correctly
implement the standard here): You cannot use template arguments
after a name unless it is somehow known that the name denotes a
template.

During the first round of standardization of C++ it was briefly
considered to add new syntax for this very example, but ultimately
it was considered unnecessary. (Something like "template g<0>(t)".)

Daveed
 
C

Chris Theis

[SNIP]
I assume you meant "Visual C++" instead of "GCC" here?
GNU is correct in refusing the code (Visual C++ does not correctly
implement the standard here): You cannot use template arguments
after a name unless it is somehow known that the name denotes a
template.
During the first round of standardization of C++ it was briefly
considered to add new syntax for this very example, but ultimately
it was considered unnecessary. (Something like "template g<0>(t)".)

Ooops, thanks for the correction Daveed. Do you happen to know how Visual
C++ treats the instantiation here, so that the unexpectedly code works?

Cheers
Chris
 
V

vandevoorde

Chris Theis wrote:
[...]
Ooops, thanks for the correction Daveed. Do you happen to know how Visual
C++ treats the instantiation here, so that the unexpectedly code
works?

The Microsoft compiler treats templates a bit like macros and basically
doesn't look at template definitions until instantiation time. (Hence
it
is unable to meet the standard 2-phase lookup requirements.) Instead,
it performs instantiation at the end of the translation unit and at
that
time it "replays" the tokens of the template definition with the
template
parameters substituted. In the example under discussion, this
replaying
for "f1<int>" happens after all the source (including the template "g")
has been seen, and therefore "g<0>" is resolved.

A consequence of doing things like this is that you can write
template<class T> void f() {
blah blah // literally, try it!
}

and the compiler will accept the code despite the nonsensical function
body (as long as you don't actually instantiate the template).

(I'm writing this not based on actual knowledge of the VC++ internals,
but based on the analysis of various cases and on knowing how some
other implementation historically worked in the same way.)

(The EDG compiler by default also accepts such example for backward
compatibility reasons. However, in its mode standard-conforming modes
if will issue an error.)

Daveed
 
I

Ioannis Vranos

The Microsoft compiler treats templates a bit like macros and basically
doesn't look at template definitions until instantiation time. (Hence
it
is unable to meet the standard 2-phase lookup requirements.) Instead,
it performs instantiation at the end of the translation unit and at
that
time it "replays" the tokens of the template definition with the
template
parameters substituted. In the example under discussion, this
replaying
for "f1<int>" happens after all the source (including the template "g")
has been seen, and therefore "g<0>" is resolved.

A consequence of doing things like this is that you can write
template<class T> void f() {
blah blah // literally, try it!
}

and the compiler will accept the code despite the nonsensical function
body (as long as you don't actually instantiate the template).

(I'm writing this not based on actual knowledge of the VC++ internals,
but based on the analysis of various cases and on knowing how some
other implementation historically worked in the same way.)

(The EDG compiler by default also accepts such example for backward
compatibility reasons. However, in its mode standard-conforming modes
if will issue an error.)


The above also compiles with Intel C++ 8.1 and VC++ 2005 February 2005 CTP.

Does the 2-phase lookup mean that the function name needs not "be
already in scope" as with the usual functions?
 
C

Chris Theis

Chris Theis wrote:
[...]
Ooops, thanks for the correction Daveed. Do you happen to know how Visual
C++ treats the instantiation here, so that the unexpectedly code
works?

The Microsoft compiler treats templates a bit like macros and basically
doesn't look at template definitions until instantiation time. (Hence
it
is unable to meet the standard 2-phase lookup requirements.) Instead,
it performs instantiation at the end of the translation unit and at
that
time it "replays" the tokens of the template definition with the
template
parameters substituted. In the example under discussion, this
replaying
for "f1<int>" happens after all the source (including the template "g")
has been seen, and therefore "g<0>" is resolved.

A consequence of doing things like this is that you can write
template<class T> void f() {
blah blah // literally, try it!
}

and the compiler will accept the code despite the nonsensical function
body (as long as you don't actually instantiate the template).

(I'm writing this not based on actual knowledge of the VC++ internals,
but based on the analysis of various cases and on knowing how some
other implementation historically worked in the same way.)

(The EDG compiler by default also accepts such example for backward
compatibility reasons. However, in its mode standard-conforming modes
if will issue an error.)

Daveed

Thanks Daveed, that was very informative!

Chris
 
V

vandevoorde

Ioannis said:
(e-mail address removed) wrote: [...]
A consequence of doing things like this is that you can write
template<class T> void f() {
blah blah // literally, try it!
}
[...]
The above also compiles with Intel C++ 8.1 and VC++ 2005 February
2005 CTP.

(I believe the Intel compiler has a --strict option that will cause
it to use the standard rules.)
Does the 2-phase lookup mean that the function name needs not "be
already in scope" as with the usual functions?

Pretty much. The exception are dependent unqualified calls
with no explicit template arguments. They come in two
variants: (1) your plain function call ("f(x, y)" where x and/or
y is dependent), and (2) simple operator invocations ("x * y"
where x and/or y is dependent). These can still appear
without actually have the function or operator be visible in
the template definition.

Daveed
 
P

philchen1978

Following might be a solution if you have to deal with the case.

template<class P>
void f()
{
P::template get<0>();
}

class A
{
public:
template<int I>
static void get()
{
cout << "hi" << endl;
}
};


int main(int argc, char *argv[])
{
f<A>();
return 0;
}

Phil
 

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

Forum statistics

Threads
474,291
Messages
2,571,455
Members
48,132
Latest member
KatlynC08

Latest Threads

Top