This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] Document pitfalls of two-stage name lookup


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]