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
Derived
inherits from Base<std::string>
, the code compiles,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 instantiated Base<T>
yet). Thus, it will search the global namespace, and find no variable called value
; consequently, it will emit an error.
Here is a typical approach to solve this problem:
template <class T>
struct Derived : public Base<T> {
int getValue() { return this->value; }
// ^^^^^^
};
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:
return Base<T>::value;
Is equally good, because it also tells the compiler that value
is inherited from the base class Base<T>
.
For what concerns deriving from Base<std::string>
, the compiler can immediately go and look up whether Base<std::string>
contains a data member named value
(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>
, where T
is unknown during the first phase of name lookup, the compiler can't tell what value
is (specializations of Base
for different T
s may even not have value
at all).
Paragraph 14.6/3 of the C++11 Standard:
In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [...] [Example:
struct A { struct B { / ... / }; int a; int Y; }; int a; template<class T> struct Y : T { struct B { / ... / }; B b; // The B defined in Y void f(int i) { a = i; } // ::a Y* p; // Y<T> }; Y<A> ya;
The members
A::B
,A::a
, andA::Y
of the template argumentA
do not affect the binding of names inY<A>
. —end example ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With