35
#include <vector>
#include <iostream>

template <class T>
class Base
{
protected:
    std::vector<T> data_;
};

template <class T>
class Derived : public Base<T>
{
public:
    void clear()
    {
        data_.clear();
    }
};

int main(int argc, char *argv[])
{
    Derived<int> derived;
    derived.clear();
    return 0;
}

I cannot compile this program. I get:

main.cpp:22: error: 'data_' was not declared in this scope

Please, could you explain why data_ is not visible in the Derived class?

Martin Drozdik
  • 12,742
  • 22
  • 81
  • 146

2 Answers2

49

To fix this, you need to specify Base<T>::data_.clear() or this->data_.clear(). As for why this happens, see here.

thegeko
  • 1,382
  • 1
  • 13
  • 18
Yuushi
  • 25,132
  • 7
  • 63
  • 81
  • Thank you! It works in both cases with Base::data_.clear() or this->data_.clear()! – Martin Drozdik Aug 20 '12 at 04:48
  • 2
    `Derived::data_.clear()` also works. – Jesse Good Aug 20 '12 at 04:50
  • 1
    For me this is a bug in compiler. It should look into bases class(es). Who cares if names is dependent o not. – Kirill Kobelev Aug 20 '12 at 04:53
  • 1
    @KirillKobelev, I would say not having `this->` is compiler limitation rather than a bug. Imagine a case where the base class is specialized for `int`, i.e. `Base` and that class doesn't have `data_`. Now compiler doesn't know whether current `Derived` is specialized for `int` or not. If compiler assumes `this->` then it will become a real bug. – iammilind Aug 20 '12 at 05:03
  • 1
    @KirillKobelev: MSVC compiler will accept `data_.clear();`, but that is because it doesn't implement two-phase name lookup. – Jesse Good Aug 20 '12 at 05:03
  • @iammilind, you would be right in a general case, if we do not have a complete example. But here, there are no specializations, error message is generated at the point of instantiation where specializations if any are already resolved. `this->` looks like something for dummies. – Kirill Kobelev Aug 20 '12 at 05:08
6

In the case of templates compiler is not able to determine if the member is really coming from base class. So use this pointer and it should work:

void clear()
{
   this->data_.clear();
}

When compiler looks the Derived class definition, it doesn't know which Base<T> is being inherited (as T is unknown). Also data_ is not any of the template parameter or globally visible variable. Thus compiler complains about it.

iammilind
  • 68,093
  • 33
  • 169
  • 336