This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [Patch] Document pitfalls of two-stage name lookup
- From: Gabriel Dos Reis <gdr at integrable-solutions dot net>
- To: Wolfgang Bangerth <bangerth at ticam dot utexas dot edu>
- Cc: gcc-patches at gcc dot gnu dot org, <mark at codesourcery dot com>
- Date: 04 Feb 2003 04:01:06 +0100
- Subject: Re: [Patch] Document pitfalls of two-stage name lookup
- Organization: Integrable Solutions
- References: <Pine.LNX.4.44.0302032029580.8447-100000@gandalf.ticam.utexas.edu>
Wolfgang Bangerth <bangerth@ticam.utexas.edu> writes:
| +The C++ standard prescribes that all names that are not
| +template-dependent are bound to their present definitions when parsing a
s/template-dependent/dependent/
| +template function or class. Only names that are template dependent are
s/template dependent/dependent/
| +bound at the point of instantiation. For example, consider
/bound/looked up/
For example consider
namespace N
{
template<typename T>
T foo(T x)
{
return cos(x);
}
}
may fail or succeed.
It fails in
#include <cmath>
int main()
{
N::foo(1.0);
}
It succeeds in
struct A { };
A cos(A) { return A(); }
int main()
{
A x;
N::foo(x);
}
| +
| +@begin example
| + template <typename T>
| + void f () {
| + foo (); // 1
| + int i = N; // 2
| + T t;
| + t.bar(); // 3
| + baz (t); // 4
| + }
| +@end example
| +
| +Here, the names @code{foo} and @code{N} appear in a context that does
| +not depend on the type of the template parameter @code{T}. The compiler
s/type of the//
| +will thus require that they are defined before it sees the template, not
s/before it sees the template/in their context of use/
Consider the above part of
struct A {
template<typename T>
void f() { ... }
void foo();
static const int N;
};
| +only before the point of instantiation. Conversely, @code{bar} and
| +@code{baz} are used in contexts that do depend on the type of @code{T},
| +so they are only looked up at the point of instantiation, and you can
| +provide declarations for them after declaring the template, but before
| +instantiating it. This is called two-stage (or dependent) name lookup,
| +and G++ only implements it since version 3.4.
| +
| +
| +This sometimes leads to situations with counter-intuitive behavior. The
according to whose intuition?
s/with counter-intuitive behavior/behaviour different from that of
non-template codes/
| +most common is probably this:
| +
| +@begin example
| + template <typename T> struct Base {
| + int i;
| + };
| +
| + template <typename T> struct Derived : public Base<T> {
| + int get_i() { return i; }
| + };
| +@end example
| +
| +In @code{get_i()}, @code{i} is not used in a template-dependent context,
| +so the compiler will look for a global variable of that name. It will
| +not look into the base class, since that is template-dependent and you
s/template-dependent/dependent/
| +may declare specializations of @code{Base} even after declaring
| +@code{Derived}, so the compiler can't really know what @code{i} would
| +refer to. If there is no global variable @code{i}, then you will get an
| +error message.
| +
| +In order to make it clear that you want the member of the base class,
| +you need to defer lookup until instantiation time, at which the base
| +class is known. For this, you need to access @code{i} in a
| +template-dependent context, by either using @code{this->i} (remember
s/template-dependent/dependent/
or you might also bring Base<T>::i into scope through a
using-declaration.
| +that @code{this} is of type @code{Derived<T>*}, so is obviously
| +template-dependent), or using @code{Base<T>::i}.
s/template-dependent/dependent/
-- Gaby