gcc: Name lookup

1 
1 13.7.2 Name Lookup, Templates, and Accessing Members of Base Classes
1 --------------------------------------------------------------------
1 
1 The C++ standard prescribes that all names that are not dependent on
1 template parameters are bound to their present definitions when parsing
1 a template function or class.(1)  Only names that are dependent are
1 looked up at the point of instantiation.  For example, consider
1 
1        void foo(double);
1 
1        struct A {
1          template <typename T>
1          void f () {
1            foo (1);        // 1
1            int i = N;      // 2
1            T t;
1            t.bar();        // 3
1            foo (t);        // 4
1          }
1 
1          static const int N;
1        };
1 
1  Here, the names 'foo' and 'N' appear in a context that does not depend
1 on the type of 'T'.  The compiler will thus require that they are
1 defined in the context of use in the template, not only before the point
1 of instantiation, and will here use '::foo(double)' and 'A::N',
1 respectively.  In particular, it will convert the integer value to a
1 'double' when passing it to '::foo(double)'.
1 
1  Conversely, 'bar' and the call to 'foo' in the fourth marked line are
1 used in contexts that do depend on the type of 'T', so they are only
1 looked up at the point of instantiation, and you can provide
1 declarations for them after declaring the template, but before
1 instantiating it.  In particular, if you instantiate 'A::f<int>', the
1 last line will call an overloaded '::foo(int)' if one was provided, even
1 if after the declaration of 'struct A'.
1 
1  This distinction between lookup of dependent and non-dependent names is
1 called two-stage (or dependent) name lookup.  G++ implements it since
1 version 3.4.
1 
1  Two-stage name lookup sometimes leads to situations with behavior
1 different from non-template codes.  The most common is probably this:
1 
1        template <typename T> struct Base {
1          int i;
1        };
1 
1        template <typename T> struct Derived : public Base<T> {
1          int get_i() { return i; }
1        };
1 
1  In 'get_i()', 'i' is not used in a dependent context, so the compiler
1 will look for a name declared at the enclosing namespace scope (which is
1 the global scope here).  It will not look into the base class, since
1 that is dependent and you may declare specializations of 'Base' even
1 after declaring 'Derived', so the compiler cannot really know what 'i'
1 would refer to.  If there is no global variable 'i', then you will get
1 an error message.
1 
1  In order to make it clear that you want the member of the base class,
1 you need to defer lookup until instantiation time, at which the base
1 class is known.  For this, you need to access 'i' in a dependent
1 context, by either using 'this->i' (remember that 'this' is of type
1 'Derived<T>*', so is obviously dependent), or using 'Base<T>::i'.
1 Alternatively, 'Base<T>::i' might be brought into scope by a
1 'using'-declaration.
1 
1  Another, similar example involves calling member functions of a base
1 class:
1 
1        template <typename T> struct Base {
1            int f();
1        };
1 
1        template <typename T> struct Derived : Base<T> {
1            int g() { return f(); };
1        };
1 
1  Again, the call to 'f()' is not dependent on template arguments (there
1 are no arguments that depend on the type 'T', and it is also not
1 otherwise specified that the call should be in a dependent context).
1 Thus a global declaration of such a function must be available, since
1 the one in the base class is not visible until instantiation time.  The
1 compiler will consequently produce the following error message:
1 
1        x.cc: In member function `int Derived<T>::g()':
1        x.cc:6: error: there are no arguments to `f' that depend on a template
1           parameter, so a declaration of `f' must be available
1        x.cc:6: error: (if you use `-fpermissive', G++ will accept your code, but
1           allowing the use of an undeclared name is deprecated)
1 
1  To make the code valid either use 'this->f()', or 'Base<T>::f()'.
1 Using the '-fpermissive' flag will also let the compiler accept the
1 code, by marking all function calls for which no declaration is visible
1 at the time of definition of the template for later lookup at
1 instantiation time, as if it were a dependent call.  We do not recommend
1 using '-fpermissive' to work around invalid code, and it will also only
1 catch cases where functions in base classes are called, not where
1 variables in base classes are used (as in the example above).
1 
1  Note that some compilers (including G++ versions prior to 3.4) get
1 these examples wrong and accept above code without an error.  Those
1 compilers do not implement two-stage name lookup correctly.
1 
1    ---------- Footnotes ----------
1 
1    (1) The C++ standard just uses the term "dependent" for names that
1 depend on the type or value of template parameters.  This shorter term
1 will also be used in the rest of this section.
1