The following code gives me a compilation error 'value' was not declared in this scope.
template<class T>
struct Base {
int value;
};
template <class T>
struct Derived : public Base<T> {
int getValue() { return value; }
};
I find it extremely odd that
- if
Derived
inherits fromBase<std::string>
, the code compiles, - if I
return Base<T>::value
, the code compiles.
Why doesn't the code compile as it is? In what way is 'value' not declared in the scope of Derived<T>::getValue()
?
Because
value
is an unqualified name, and during the first phase of name lookup, the compiler will have no clue that this is a data member inherited from a base class (it hasn't instantiatedBase<T>
yet). Thus, it will search the global namespace, and find no variable calledvalue
; consequently, it will emit an error.Here is a typical approach to solve this problem:
Explictly dereferencing
this
tells the compiler that the name that follows is the name of a (possibly inherited) data member, and the lookup should be delayed to the point where the member function is actually instantiated. Of course, your solution of doing:Is equally good, because it also tells the compiler that
value
is inherited from the base classBase<T>
.For what concerns deriving from
Base<std::string>
, the compiler can immediately go and look up whetherBase<std::string>
contains a data member namedvalue
(because it does not depend on any template parameter) and if that is the case, it will be able to determine that the expression is well-formed.However, if your base class is
Base<T>
, whereT
is unknown during the first phase of name lookup, the compiler can't tell whatvalue
is (specializations ofBase
for differentT
s may even not havevalue
at all).Paragraph 14.6/3 of the C++11 Standard: