[Patch] Document pitfalls of two-stage name lookup

Wolfgang Bangerth bangerth@ticam.utexas.edu
Tue Feb 4 02:35:00 GMT 2003


We get a lot of reports for alleged problems which really are due to lack 
of understanding of two-stage name lookup. Here's a first draft (of my 
limited understanding) of the pitfalls of this for the non-bugs section of 
trouble.texi. Criticism is invited, in particular from the ones who wrote 
this part of the compiler.

Note that present CVS still doesn't implement two-stage name lookup 
correctly (PR 9476: two-stage name lookup not applied to function calls), 
but I wrote the text as if it did.

Something similar should eventually also go to the webpages to a prominent 
place in bugs.html. 

W.

-------------------------------------------------------------------------
Wolfgang Bangerth             email:            bangerth@ticam.utexas.edu
                              www: http://www.ticam.utexas.edu/~bangerth/


Index: trouble.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/trouble.texi,v
retrieving revision 1.14
diff -u -r1.14 trouble.texi
--- trouble.texi	24 Jan 2003 15:57:41 -0000	1.14
+++ trouble.texi	4 Feb 2003 02:29:56 -0000
@@ -851,6 +851,7 @@
 
 @menu
 * Static Definitions::  Static member declarations are not definitions
+* Templates and base classes:: Accessing members of base classes and templates
 * Temporaries::         Temporaries may vanish before you expect
 * Copy Assignment::     Copy Assignment operators copy virtual bases twice
 @end menu
@@ -891,6 +892,75 @@
 does not conform to the standard: @command{g++} reports as undefined
 symbols any static data members that lack definitions.
 
+
+@node Templates and base classes
+@subsection Templates, name lookup, and accessing members of base classes
+
+@cindex base class members
+@cindex two-stage name lookup
+@cindex dependent name lookup
+
+The C++ standard prescribes that all names that are not
+template-dependent are bound to their present definitions when parsing a
+template function or class.  Only names that are template dependent are
+bound at the point of instantiation.  For example, consider
+
+@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
+will thus require that they are defined before it sees the template, not
+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
+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
+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
+that @code{this} is of type @code{Derived<T>*}, so is obviously
+template-dependent), or using @code{Base<T>::i}.
+
+Note that most compilers get this wrong and accept above code without an
+error.  However, this is spurious, since they just don't implement
+two-stage name lookup correctly.  This includes G++ versions prior to
+3.4.
+
+
 @node Temporaries
 @subsection Temporaries May Vanish Before You Expect
 
@@ -993,7 +1063,7 @@
 
 g++ implements the ``intuitive'' algorithm for copy-assignment: assign all
 direct bases, then assign all members.  In that algorithm, the virtual
-base subobject can be encountered many times.  In the example, copying
+base subobject can be encountered more than once.  In the example, copying
 proceeds in the following order: @samp{val}, @samp{name} (via
 @code{strdup}), @samp{bval}, and @samp{name} again.
 



More information about the Gcc-patches mailing list