Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-02-14 13:39:52


Gabriel Dos Reis <gdr_at_[hidden]> writes:

> "Giovanni Bajo" <giovannibajo_at_[hidden]> writes:
>
> | David Abrahams wrote:
> |
> | >> struct A {
> | >> typedef int M;
> | >>
> | >> template <class M>
> | >> void foo(void) {
> | >> M m; // which M is this?
> | >> }
> | >> };
> | >>
> | >> I know the C++ committe is discussing this issue at this moment. The
> | >> argument would be that "M" names the typedef because it's "more
> | >> stable" than the template parameter (which could get renamed in an
> | >> out-of-class definition). See also http://gcc.gnu.org/PR13967 for a
> | >> detailed discussion.
> | >
> | > I'm sorry, but that's insane from a usability POV. C++ already has
>
> Dave, I got the copy of the message you sent. While the rules as
> currently defined are not clear and not even what you would expect, I
> don't agree that "insane" (or such words) are qualifications that
> should be used if you wanted a technical discussion about your
> request.

I don't think I really was trying to start a technical discussion. I
was just trying to register a strong opinion with someone (you) who is
working on the problem.

> | > too many places where something far away can be chosen instead of the
> | > "obvious" alternative close by (see ADL).
>
> When it comes to name look up, I think "obvious" does not carry any
> meaning that would be of help -- I'm not just speaking of what C++
> current rules say about name look-up.
>
> | I'm not advocating that, I'm just saying that it's how GCC currently
> | works and it seems to be a gray area of the standard. My personal
> | opinion is that GCC is wrong: I agree with you that the template
> | parameter should be found on name lookup.
>
> And it should be also pointed out that GCC is not the only compiler
> that interprets the construct differently from what you would consider
> "obvious". And the problem has to do with the way the current
> rules are worded (the least that can be said is that the rules are
> incomplete). We have had a long discussion about this on the CWG
> reflector. This undoubtely is going to be debated again at the next
> meeting.
>
> One thing that should be kept in the fore is that, when you provide an
> in-class definition of a member function, that definition gets
> re-evaluated as an out-of-class definition; that is not a requirement
> but, it is a common strategy in order to take into account use of
> names that are declared "later" in the class. If the re-evaluation
> of the definition in the completed scope differs from the evaluation
> of the in-class definition, then the program is ill-formed and no
> diagnostic is required. Some compilers however, as a QoI, issues
> diagnostics on the cases they can catch. For example,
>
> typedef int A;
> struct B {
> A x;
> void f();
> struct A { };
> };
>
> is ill-formed and it is likely that your favorite compiler will complain.
>
> Now, what is the relation with the member template case presented above?
> When you have something like
>
> struct A {
> typedef int M;
>
> template <class M>
> void foo(void) {
> M m; // which M is this?
> }
> };
>
> it gets evaluated as if
>
> struct A {
> typedef int M;
> template<class M> void f();
> };
>
> template<class M>
> void A::f()
> {
> M m;
> }
>
>
> The name look-up rules as currently defined do not attach the template
> parameters to the lexical scope of the member template, so when in the
> body of A::f(), the scope stack looks like this:
>
> namespace scope (global scope)
> template scope (contains class M)
> class A scope (contains typedef int M;)
> A::f()-body scope
>
> Therefore, look-up for M finds the class-scope declaration "typedef
> int M;" -- which is the `"obvious" alternative close by' if I were to
> use your words

Not AFAICS. The template parameter is closer to the use of M and to
my eye, much more obvious.

> In order to choose the other `"obvious" alternative close by', the
> out-of-class definition for member template syntax should have been
>
> A:: // <-- Note the enclosing A
> template<class M>
> void f()
> {
> M m;
> }
>
> which would yield the scope stack
>
> namespace scope (global scope)
> class A scope (contains typedef int M;)
> template scope (contains class M)
> A::f()-body scope
>
> The point of the discussion we reached last week (with no vote to evaluate
> consensus) was that, we would change/clarify the lookup rules so that
> when the compiler sees the out-of-class definition of a
> member-template it does a resuffling of the scope stack to make it
> look like what one would get did we have the "right" syntax (as shown above).
>
> The case posted by David Vandevoorde on the newsgroups is not revolved
> by the change I mentioned above. It should also be pointed out the
> decision of have a member name hides an enclosing template-parameter
> name was a conscious decision, made after debate.
>
> Now, just to illustrate the point "name look up" is not an "obvious"
> thing; let's condider the following example
>
> template<class T>
> struct S {
> typedef char C;
> template<class>
> int f();
> };
>
> Consider the following two "possible" out-of-class definitions
>
> // alternative #1
>
> template<class C>
> template<class U>
> int S<C>::f()
> { return sizeof (C); }
>
> // alternative #2
> template<class T>
> template<class C>
> int S<T>::f()
> { return sizeof (C); }
>
>
> As interpreted by at least 3 or 4 major compilers, the "C" in the body
> consistently refers to S<>::C. If changed abruptly to the "obvious"
> close by, then the two definitions are not equivalent

Right.

> and in the "C" in the body of #1 will not be the "obvious" close by
> (template-parameter).

Why not? It seems to me you could design the rules so the "C" in
each case referred to a (different) template parameter.

> During the discussion on the CWG reflector, we
> introduced the notion of "valid template-parameter renaming"
> (which is similar to what FP community calls valid "alpha conversion").
> I proposed that if an out-of-class definition of a member template uses
> an invalid template-parameter renaming, then the program is
> ill-formed. The idea is to avoid misunderstanding about the `"obvious"
> alternative close by' between programmer and compiler.

That sounds like it might be a good idea.

> | > Introducing a typedef in an
> | > enclosing namespace should not affect the meaning or well-formedness
> | > of a use of a template parameter, especially because this sort of
> | > thing is liable to happen due to changes in #includes.
>
> Dave, I can't find anything like the one you're describing in the
> example you gave. Class-scope declarations are "preserved" against
> outside perturbation -- that is what the re-evaluation rules is about.

Yeah, I misread the example.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk