17

The following code cannot compile - use of undeclared identifier. I use GCC and XCode for compilation.

Everything is in a single header file.

include "MyArray.h"

template <typename T>
class MyBase {
public:
  MyBase();
  virtual ~MyBase();
  void addStuff(T* someStuff);
protected:
  MyArray<T*> stuff;
};

template <typename T>
MyBase<T>::MyBase() {}
template <typename T>
MyBase<T>::~MyBase() {}

template <typename T>
void MyBase<T>::addStuff(T* someStuff) {
  stuff.add(someStuff);
}

// ---------------------

template <typename T>
class MyDerived : public MyBase<T> {
public:
  MyDerived();
  virtual ~MyDerived();
  virtual void doSomething();
};

template <typename T>
MyDerived<T>::MyDerived() {}
template <typename T>
MyDerived<T>::~MyDerived() {}

template <typename T>
void MyDerived<T>::doSomething() {
  T* thingy = new T();
  addStuff(thingy); //here's the compile error. addStuff is not declared.
}

Does anyone have an explanation? Thanks in advance!

user1414745
  • 1,317
  • 6
  • 25
  • 45
  • @jua you definitely need to lookup the cursed dependent base lookup rules regarding unqualified names. what you say is incorrect. a conforming compiler will require it. – Johannes Schaub - litb May 24 '12 at 20:07

4 Answers4

35

try

this->addStuff(thingy);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
7

It's due to template inheritance. In such case you should mannualy specify using for base methods:

template <typename T>
MyDerived<T>::doSomething() {
  using MyBase<T>::addStuff;
  T* thingy = new T();
  addStuff(thingy); 
}

or do it by this pointer:

template <typename T>
MyDerived<T>::doSomething() {
  T* thingy = new T();
  this->addStuff(thingy); 
}
inkooboo
  • 2,904
  • 1
  • 19
  • 24
6

There are several issues:

  1. Missing semicolons after class definitions.
  2. Missing type for doSomething method declaration/definition.
  3. Missing type for definition of addStuff method.

After fixing that it seems to work.

Edit: As you have fixed the syntax errors and it still does not work. As others have suggested your compiler may require you to call the addStuff method with this-> prefix:

this->addStuff(thingy);
Juraj Blaho
  • 13,301
  • 7
  • 50
  • 96
  • 1
    I think, that should not work as the Standard. `this->` part is a requirement here. – Nawaz May 24 '12 at 10:35
  • @Nawaz: MSVC2010 works too. Can you post a citation from standard why it should not work? – Juraj Blaho May 24 '12 at 10:45
  • @Nawaz: No, that's not a requirement in this case. See my comment to your answer for details. – Mike Seymour May 24 '12 at 10:47
  • @JurajBlaho: Actually, `addStuff` is indeed a dependent name, but `this->` is not needed, as the compiler gets that hint from the *type* of the argument. I'm going to quote Mike's comment on my answer (as I will delete it soon) : *`addStuff(thingy)` is a dependent expression (since the type of thingy depends on T), and so name lookup doesn't happen until the template is instantiated. At that point, the type of the base class is known, and so `MyBase::addStuff` is considered. Thus there is no need to add this in this case.* – Nawaz May 24 '12 at 10:51
  • 1
    @JurajBlaho: If you want to know more about two-phase name lookup, then see this : [The Dreaded Two-Phase Name Lookup](http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html) – Nawaz May 24 '12 at 10:53
  • @JurajBlaho I agree with Mike Seymour and Nawaz, no `this->` needed. I can't remove my answer now because it is accepted, for whatever reason. – juanchopanza May 24 '12 at 12:12
  • 1
    @mike you are wrong. the this-> prefix is required. that the name is dependent is not sufficient for it to be looked up in the dependent base class. gcc fixed this bug in their latest release. – Johannes Schaub - litb May 24 '12 at 19:52
  • @JohannesSchaub-litb: Yes, you're right (the relevent bit of the standard is C++11 14.6.2/3, if anyone's interested). I should probably stop pretending that I understand the name lookup rules. – Mike Seymour May 25 '12 at 06:47
  • @Mike Seymour: But who does understand it, when at least two major compiler vendors did it wrong. – Juraj Blaho May 25 '12 at 07:38
3

use this pointer to invoke the addStuff method i.e

this->addStuff(thingy);
shofee
  • 2,079
  • 13
  • 30