wrote:
Victor said:
On 7/23/2011 7:39 AM, Johannes Schaub wrote:
Tom wrote:
Hi NG,
The following example does not compile using g++. The compiler says
"error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
of the derived class:
template<typename T>
class MyBase
{
protected:
int iMyVal;
};
template<typename T>
class MyDerived : public MyBase<T>
{
void MyFunction()
{
// this->iMyVal = 10;
iMyVal = 10;
}
};
int main()
{
MyDerived<int> derived;
return 0;
}
[snip]
The FAQ has it subtly wrong. Which is why I didn't gave him the FAQ
entry. Where the Standard says that the base declaration is not found
because the name is unqualified, the FAQ says that the declaration is not
found because the name is non-dependent. This is a common misconception
Let's do a reality check.
There is an error when "imMyVal" is a non-dependent name, and a concrete
example has been given.
Would there have been an error if instead of "imMyVal" there had been a
dependent name (of course, it may then have to be of different syntactic
form)?
Yes there would have been. The C++ Standard specifically says: Unqualified
lookup ignores the dependent base classes both at the time of definition of
the template and at instantiation of the template.
If the answer to that question is "no", then we have established that at
least within the framework of this concrete example the dependency of
the name corresponds directly to the error, i.e. that in this example
dependent/non-dependent determines the error, as the FAQ says.
If the answer, on the other hand, is "yes", then there should exist a
concrete example of that?
I can't show an example using a function call, because if you make the name
dependent, the rules for lookup of dependent function names dictate that
unqualified lookup only consideres declarations of the definition context.
Declarations visible only when instantiating are only considered by argument
dependent lookup.
But still, the following code contains a dependent name "f", and will ignore
the dependent base class, even if the lookup for dependent function names
would otherwise have looked-up in the scope of the class at the time of
instantiation again.
Example:
template<typename T>
struct A {
void f(T) { }
};
template<typename T>
struct B : A<T> {
void g() {
f(T());
}
};
int main() { B<int> b; b.g(); }
I can argue for my position by noting that the Standard doesn't define what
happens to the dependent base class in the lookup within the definition
context, if we would strike out the rule that unqualified lookup ignores
dependent base class. The obvious interpretation would be to say "We have to
look in the definition context into a base class that is dependent. Hence we
have to delay lookup, waiting for it to become complete". The Standard
doesn't need to handle this case because it explicitly says that unqualified
lookup ignores dependent base classes, like I said above.
In fact the "obvious interpretation" was spelled out in the C++98 Standard,
which worded the rule differently (but to the same effect): It said that
dependent base classes are not examined during lookup until the class is
instantiated. The absence of a definition of the case of what happens to
dependent base classes for lookup at the definition context was answered by
that. Later DRs that were incorporated into C++03 noted that this is
unnecessarily convoluted and easily leads to misinterpretations and changed
it to simply say that unqualified lookup ignores dependent base classes.
I can show non-call examples that prove my point:
template<typename U>
struct A {
typedef int T;
};
template<typename T>
struct B : A<T> {
void f() {
T t;
}
};
The dependent name "T" is not found in the dependent base class, even though
it would if ignoring dependent base classes would solely be done because of
names being non-dependent. You may argue that lookup of names like "T" above
is not redone at instantiation, but I think that the spec requires it to be,
because "T" is type-dependent. Whether or not that is intuitive is another
matter, though. C++98 explicitly ruled that the "T" declared in the
dependent base class at instantiation time cannot hide the template
parameter when lookup is done at instantiation again.