0

consider the following code:

template<class T>
class Base {
  public:
    void doSomething(){}
};

template<class T>
class Derived : public Base<T> {
  public:
    void doMore() {
      doSomething(); //Affected line
    }
};

In the line commented with "affected line" g++ (4.7) says:

test.cc:11:16: error: there are no arguments to ‘doSomething’ that depend on a template parameter, so a declaration of ‘doSomething’ must be available [-fpermissive]

Now I am wondering:

  • If the template parameter T would not be there, this error would not occure. What is the difference?
  • g++ obviously is able to resolve this problem (if I add -fpermissive it compiles fine). I am assuming that g++ tries to make the best experience for me as the "user" (programmer). What are the advantages for me when g++ does not accept this code?

Thanks! Nathan

Nathan
  • 7,099
  • 14
  • 61
  • 125
  • 4
    Change to `this->doSomething()` (or `Base::doSomething()`), as `doSomething()` is dependent on the type of `T`. – hmjd May 29 '12 at 11:33
  • @hmjd: that is interesting.. can you give a brief description how adding `this->` helps? – Asha May 29 '12 at 11:41
  • 1
    See [this question](http://stackoverflow.com/questions/10735611/use-of-undeclared-identifier-in-c-with-templates-and-inheritance/10735684#10735684) and answers therein. – juanchopanza May 29 '12 at 11:44
  • @Asha, `this->` tells the compiler the name is a member, so name lookup is delayed until phase 2 (instantiation) when the type of the base class is known and the declarations of its members are visible – Jonathan Wakely May 29 '12 at 13:13

2 Answers2

2

If you do not add this or Base<T> you write code that is not standard conforming - GCC wants to prevent you from doing this. See also the Changelog entry for GCC 4.7:

G++ now correctly implements the two-phase lookup rules such that an unqualified name used in a template must have an appropriate declaration found either in scope at the point of definition of the template or by argument-dependent lookup at the point of instantiation. As a result, code that relies on a second unqualified lookup at the point of instantiation to find functions declared after the template or in dependent bases will be rejected. The compiler will suggest ways to fix affected code, and using the -fpermissive compiler flag will allow the code to compile with a warning.

template <class T>
void f() { g(T()); } // error, g(int) not found by argument-dependent lookup
void g(int) { } // fix by moving this declaration before the declaration of f

template <class T>
struct A: T {
  // error, B::g(B) not found by argument-dependent lookup
  void f() { g(T()); } // fix by using this->g or A::g
};

struct B { void g(B); };

int main()
{
  f<int>();
  A<B>().f();
}

(found here: http://gcc.gnu.org/gcc-4.7/changes.html).

cschwan
  • 3,283
  • 3
  • 22
  • 32
1

This is covered in the GCC Verbose Diagnostics wiki page.

What are the advantages for me when g++ does not accept this code?

It conforms to the standard and agrees with other compilers, ensuring your code is portable and correct.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • OK, it conforms to the standard. But I must say that it annoys me that the standard forces me to write "this->doSomething()" or use "-fpermissive" and I do not understand why the standard could not be "nicer". – Nathan May 29 '12 at 13:52
  • 1
    If you specialize `Base` so that `Base::doSomething` is a data member, not a member function, then it would be invalid to instantiate `Derived::doMore` because it would try to "call" a data member. So the type of names in a base class, or whether they even exist at all, can't be known until instantition time, so there is no point looking in the base class before instantiation. To tell the compiler the name might come from the base class and to wait until instantition to do the lookup, you must qualify the name or use `this->`, otherwise lookup will fail to find it. – Jonathan Wakely May 29 '12 at 15:17
  • 1
    ... an alternative would be for the compiler to sometimes find it at definition time, then sometimes "unfind" it if it's not there at instantiation time, which would be inconsistent and even more confusing. If you want inconsistent "sometimes works this way, sometimes works that way" then try PHP ;-) The standard _attempts_ to give a single, unambiguous set of rules about how templates are compiled, and one of the consequences is that in templates unqualified name lookup never looks in dependent base classes. – Jonathan Wakely May 29 '12 at 15:24