Boost logo

Boost :

From: Deane Yang (deane_yang_at_[hidden])
Date: 2004-02-14 12:34:42


I apologize in advance for a really naive question,
but as an unsophisticated C++ programmer (at least relative
to the boost experts), why can't we simply ban this kind of code?

In other words, if "M" has already been defined within class scope
for something else, it should not be allowed as a template parameter name.

Code like this just makes my head spin, so I can't see how allowing
it is to anyone's benefit.

And can't situations like this be avoided with coding practices that
dictate different styles for naming typedefs from template parameters?

I would, of course, still want the compiler to at least warn me if
something like this occurs.

Gabriel Dos Reis wrote:
> "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.
>
> | > 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 I already disagree with.
>
> 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 and in the "C"
> in the body of #1 will not be the "obvious" close by
> (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.
>
>
> | > 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.
>
> -- Gaby
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>


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