|
Boost : |
From: David Abrahams (dave_at_[hidden])
Date: 2002-12-01 16:11:15
Beman Dawes <bdawes_at_[hidden]> writes:
> At 08:11 PM 11/28/2002, David Abrahams wrote:
>
> >> AFAIK, Metrowerks is correct, and the other compilers intend to detect
> >these errors in the future.
> >>
> >> The fix is usually to add qualification. For example,
> >foo::out_of_range_bit.
> >
> >The fix is usually to make sure that the appropriate declaration of a
> >non-dependent name is visible before the name is used. Extra
> >qualification doesn't usually help AFAICT.
> >
> >Oh, I guess that if the name is a member of a base class, then the fix
> >is to write ``this->member_name'' or ``BaseClass::member_name''
> >instead of just ``member_name''. That can be viewed as adding
> >qualification.
>
> Yes, that was the case that came up in other libraries.
>
> > However, that doesn't _appear_ to be the problem in the
> >case below, and in any case I recomment using ``this->'' when possible
> >because it's more reliable.
>
> Hum... I'll take your word for it, but to tell the truth I have
> trouble understanding what either ``this->member_name'' or
> `BaseClass::member_name'' adds. And the format library case wasn't a
> member name at all, it was an enum name, IIRC.
Which is why (unless the enum was a member of a dependent base class)
adding qualification is probably not the right fix in this case.
> I guess I need a C++ for dummies level description of why these
> names are not visible, and why adding
> this-> or qualification makes the names visible.
It's pretty simple:
0. A "dependent" name is one whose meaning depends on the type or
value of a template parameter.
1. templates are parsed in phase 1 and all non-dependent names are
bound at that point. Any unqualified names which are not followed
by dependent arguments (e.g. some_name(x), where x is of type T)
are considered to be non-dependent.
1.5 It is in phase 1 that the compiler also decides whether each name
is referring to a member or a non-member. I guess the theory is
that we don't want our templates to suddenly start using members
instead of non-members because we instantiated them with a base
class that has an unfortunate member name:
template <class T> void f(T x);
template <class B> struct D : B
{
D() { typedef typename B::some_type some_type; f(some_type()); }
};
struct Base
{
f(int);
typedef int some_type;
};
D<Base> x; // uh-oh?
In this case, f is dependent, because ADL says to look it up based
on argument types. However, phase 1 parsing determines that it's a
non-member name because it's not defined in D or any of its
non-dependent bases (of which it has none).
2. When templates are instantiated, phase 2 lookup goes into effect
and dependent names are bound.
3. If a base class is dependent on (or is) a template parameter, you
can't know the base's exact definition until all specializations
have been seen, so unqualified names never refer to members of
dependent bases. They are always treated as non-dependent and bound
in phase 1 at the template's point-of-definition. By the time we
get to phase 2 and know the definition of the actual base, it's too
late.
4. If the template has dependent bases, and the name is not found in
the template itself, you can make the name dependent by adding
this->, since then its definition may depend on the base class.
So, adding this-> or BaseClass:: doesn't actually make the names
visible. Instead it
a. Marks the name as a member in phase 1
b. delays lookup of the names until phase 2 when they might be
visible.
HTH,
Dave
-- David Abrahams dave_at_[hidden] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk