Tuesday, January 19, 2010

Two-stage name lookup issues with template code

The C++ standard prescribes that all names that are not dependent on template parameters are bound to their present definitions when parsing a template function or class. Only names that are dependent are looked up at the point of instantiation. This distinction between lookup of dependent and non-dependent names is called two-stage (or dependent) name lookup. G++ implements it since version 3.4.

Two-stage name lookup sometimes leads to situations with behavior different from non-template codes. The most common is probably this:


//vec.h

#include

template class Vec : public std::vector {
public:
Vec() : std::vector () {}
Vec(int s) : std::vector (s) {}
T& operator[] (int i) { return at(i);}
const T&operator[] (int i) const { return at(i); }
};


the call to at() is not dependent on template arguments (there are no arguments that depend on the type T, and it is also not otherwise specified that the call should be in a dependent context). Thus a global declaration of such a function must be available, since the one in the base class is not visible until instantiation time. The compiler will consequently produce the following error message:


vec.h: In member function ‘T& Vec::operator[](int)’:
vec.h:7: error: there are no arguments to ‘at’ that depend on a template parameter, so a declaration of ‘at’ must be available
vec.h:7: error: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
vec.h: In member function ‘const T& Vec::operator[](int) const’:
vec.h:8: error: there are no arguments to ‘at’ that depend on a template parameter, so a declaration of ‘at’ must be available


To make the code valid either use this->at(i), or vector::at(i). Using the -fpermissive flag will also let the compiler accept the code, by marking all function calls for which no declaration is visible at the time of definition of the template for later lookup at instantiation time, as if it were a dependent call. Using -fpermissive to work around invalid code is not recommended however, and it will also only catch cases where functions in base classes are called, not where variables in base classes are used (as in the example above).

Some compilers (including G++ versions prior to 3.4) get these examples wrong and accept above code without an error. Those compilers do not implement two-stage name lookup correctly.

1 comment:

Axe Your Ex said...

i am using cygwin I am getting these errors when i compile sim_routing.cc program by this command
../../bin/cxx sim_routing.cc
g++ -Wall -o sim_routing sim_routing.cxx
../../common/priority_q.h : In member function 'bool guardedQueue::Validate(Const char*);
error : there are no argument to 'strcat' that depend on template parameter so a declaration of 'strcat' must be avaible.
error :
error : there are no argument to strcat that depends on template parameter,so declaration to strcat must be avaible.

when i use CXXFLAGS+=-fpermissive
compiler accept the commands but not removes these errors
so how these errors can be removed