1

I have a template struct which inherits another template struct. It fails compilation in different compilers (in VS2017 and clang on linux). A simple change in the code fixes it. The code is:

template<typename T>
struct base {
    int GetValue2() { return 0; }
};

template<typename T>
struct derived : public base<T>
{
    int GetValue() { return GetValue2(); }
};

int main() {
    derived<int> a;

    return 1;
}

If I change the line int GetValue() { return GetValue2(); } to: int GetValue() { return this->GetValue2(); } everything compiles just fine.

Does anyone have an idea what's going on?

Yoel Perl
  • 11
  • 1

1 Answers1

0

There is a two-stage name lookup here.

In GetValue(), GetValue2 is not used in a dependent context, so the compiler will look for a name declared at the enclosing namespace scope (which is the global scope here).

It will not look into the base class, since that is dependent and you may declare specializations of Base even after declaring Derived, so the compiler can't really know what i would refer to. If there is no global variable i, then you will get an error message.

In order to make it clear that you want the member of the base class, you need to defer lookup until instantiation time, at which the base class is known. For this, you need to access i in a dependent context, by either using this->i (remember that this is of type Derived*, so is obviously dependent), or using Base::i. Alternatively, Base::i might be brought into scope by a using-declaration.

template<typename T>
struct base {
    int GetValue2() { return 0; }
};

template<typename T>
struct derived : public base<T>
{
    int GetValue_using() { 
        using base<T>::GetValue2; // won't compile with gcc, place it outside the function (ok with clang and msvc)
        return GetValue2(); 
    }
    int GetValue_this() { return this->GetValue2(); }
    int GetValue_base() { return base<T>::GetValue2(); }
};

int main() {
    derived<int> a;
    return 1;
}
Vasilij
  • 1,861
  • 1
  • 5
  • 9