Topic: declare a typedef as a friend


Author: girod@dshp01.trs.ntc.nokia.com (Marc Girod)
Date: 1996/09/27
Raw View
I'd like to refine my own question.

If this is wrong because a friend specification must include the
keyword 'class':

class X {
  template <class T> friend typename Y<T>::session;
};

...but that is correct, at least when instantiated with an actual
'class' type:

template <class T> class Y {
  friend class T;
};

..shouldn't the following be correct then under the same terms?

class X {
  template <class T> friend class Y<T>::session;
};

My compiler says:

Error 459: "foo.C", line 7 # 'session' is used as a type, but has not been defined as a type.
      template <class T> friend class Y<T>::session;

Best Regards!
--
Marc Girod                                   Phone:  +358-0-511 27703
Nokia Telecommunications   P.O. Box 12       Fax:    +358-0-511 27432
Kilo RD 4                  FIN-02611 Espoo   marc.girod@ntc.nokia.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: bradds@concentric.net (Bradd W. Szonye)
Date: 1996/09/27
Raw View
Marc Girod <girod@dshp01.trs.ntc.nokia.com> wrote in article
<1ypw3aoe7p.fsf@dshp01.trs.ntc.nokia.com>...
> >>>>> "BS" == Bradd W Szonye <bradds@concentric.net> writes:

> Hello Bradd!
>
> Thanks both for your apologies and for your good study of the draft.

No problem.

> template <class T> class Y {
>     typedef T session;
>   friend class session;
> };

Unfortunately, this is in fact illegal. You simply may not precede a
"typedef-name" (ie, "session") with a "class-key" (ie, "class). Section
7.1.3 (4) says this explicitly:

  . . . The
  typedef-name  shall not be used after a class, struct, or union prefix
  and not in the names for constructors and destructors within the class
  declaration itself.

Also, 9.1 [5]:

5 A typedef-name (_dcl.typedef_) that names a class is a class-name, but
  shall  not  be  used  in  an   elaborated-type-specifier;   see   also
  _dcl.typedef_.

> template <class T> class Y {
>   friend class T;
> };

This one, however, is explicitly well-defined, by 14.2.1 [2]:

2 A template type-parameter can be used in an elaborated-type-specifier.
  [Example:
          template<class T> class A {
                  friend class T;
                  class T* p;
                  class T;        // error: redeclaration of template
parameter T
                                  // (a name declaration, not an
elaboration)
                  // ...
          }

   --end example]

So it seems you've found two places where current compilers typically fail:
they will compile the first class above, but not the second one.

> I have always thought at a nested typedef as a member... My turn to
> cite the draft, in a comment inside an example:
>
> 11   Member access control                    [class.access]
> [ ... ]
> 5 [ ... ]
>   [Example:
>           class A {
>               typedef int I;      // private member
>
> That is, I take your point (1), but would reject (2).

You're right; I was wrong about this. From 9.2 [1]:

  . . . Members of
  a  class  are  data  members,  member functions (_class.mfct_), nested
  types, and enumerators. . . .  Nested  types  are  classes
  (_class.name_, _class.nest_) and enumerations (_dcl.enum_) defined  in
  the class, and arbitrary types declared as members by use of a typedef
  declaration  (_dcl.typedef_).

Now, given 14.13 (3):

3 A member of a class template may be declared to be a  friend.

This implies that the requirement (in 11.4 [2]) that a friend class
declaration name an elaborated type is wrong, or the definition of
"elaborated-type-specifier" (in 7.1.5.3) is wrong. One of the two should
allow the declaration "friend typename T" where T is a "typedef-name."
Either that or 14.13 should clarify the issue by mentioning that this
oddball case is explicitly excluded from friendship declarations.

I agree that "friend typename T" *should* be well-defined where T is a
typedef-name. It seems that either 11.4, 7.1.5.3, or 14.13 needs fixing.
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~bradds


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Roly Perera" <rolyp@private.nethead.co.uk>
Date: 1996/09/23
Raw View
Bradd W. Szonye wrote:

> > template <class T> class Y {
> >   public:
> >     typedef T session;
> > };
> >
> > class X {
> >   template <class T> friend typename Y<T>::session;
> >     void foo() {}
> > };
> >
> > class Z: public Y<Z> {
> >     void bar(X x) { x.foo(); }
> > };
> >
> >       The test case appears to be invalid because it tries to declare a
> >       typedef as a friend.  We lowered the priority because the
compiler
> >       still needs to diagnose that error.  Another defect will be
> >       submitted for a modified test case which should be conforming.
>
> It has nothing to do with the typedef. Z simply does not have any access
to
> X whatsoever (since it has no public members). X is a friend of Y, yes,
but
> *not* of Z. Friendship is not inherited, to avoid opening up "access
holes"
> through unanticipated derivation. If bar() were in  Y and inherited by Z,
> then Y::bar() could access x.foo(). Even so, an override of Z::bar()
> *still* has no access to X.

You've misunderstood the original posting.  X's templated friend
declaration doesn't declare Y as a friend - it declares Y<T>::session as a
friend, which is a typedef defined within template class Y to be equivalent
to Y's type parameter.

> Please read your compiler's manuals (or, preferably, a good book such as
> the ARM, C++ 2nd Ed, Lippman, etc.) carefully before asking questions
like
> this on a standards newsgroup. It's one thing to ask "Does this feature
> belong in the language" and another to say "I don't know if this is
right,
> is it?" The former questions belong in comp.std.c++ and the latter in
> comp.lang.c++.moderated. In general, requests for help are better suited
to
> the "lang" groups than the "std" groups. Reading the FAQs doesn't hurt
> either.

Nor does reading the posting before replying to it :-)

> I'm surprised there was no comment from the moderators on this.

--
Roly Perera
----
Interactive Computers Ltd
3 Cumberland Road
Acton
London  W3 6EX
Phone: +44 (956) 414 395
Phax:  +44 (181) 932 2490
Email: rolyp@private.nethead.co.uk
----
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: bradds@concentric.net (Bradd W. Szonye)
Date: 1996/09/24
Raw View
Roly Perera <rolyp@private.nethead.co.uk> wrote in article
<01bba8d9$448a3b20$2b8549c2@my-computer>...
> Bradd W. Szonye wrote:
> > Marc Girod wrote:
>
> > > template <class T> class Y {
> > >   public:
> > >     typedef T session;
> > > };
> > >
> > > class X {
> > >   template <class T> friend typename Y<T>::session;
> > >     void foo() {}
> > > };
> > >
> > > class Z: public Y<Z> {
> > >     void bar(X x) { x.foo(); }
> > > };
> > >
> > It has nothing to do with the typedef. Z simply does not have any
access to
> > X whatsoever (since it has no public members). X is a friend of Y, yes,
but
> > *not* of Z. Friendship is not inherited, to avoid opening up "access
holes"
> > through unanticipated derivation. If bar() were in  Y and inherited by
Z,
> > then Y::bar() could access x.foo(). Even so, an override of Z::bar()
> > *still* has no access to X.
>
> You've misunderstood the original posting.  X's templated friend
> declaration doesn't declare Y as a friend - it declares Y<T>::session as
a
> friend, which is a typedef defined within template class Y to be
equivalent
> to Y's type parameter.

You're right, I did misunderstand the problem. After much searching through
the working papers, I've come up with an alternative explanation. Bear with
me, there's several sections of the WP involved in this problem.


11.4 Friends

2 ... An elaborated-type-specifier shall be used in a friend declaration
for a class; see
_dcl.type.elab_ .(footnote 3) [Note: _dcl.type.elab_ further describes the
syntax
of friend class declarations.]

(3) The class-key of the elaborated-type-specifier is required.


  7.1.5.3  Elaborated type specifiers                    [dcl.type.elab]

1         elaborated-type-specifier:
                  class-key ::opt nested-name-specifieropt identifier
                  enum ::opt nested-name-specifieropt identifier
          class-key:
                  class
                  struct
                  union

2 If an elaborated-type-specifier is the sole constituent of a  declara-
  tion, the declaration is ill-formed unless it has one of the following
  forms:
  --      class-key identifier ;
3 --      friend class-key identifier ;
4 --      friend class-key ::identifier ;
          friend class-key nested-name-specifier identifier ;

6 The class-key or enum keyword present in the elaborated-type-specifier
  shall  agree  in  kind  with  the declaration to which the name in the
  elaborated-type-specifier refers.  This rule also applies to the  form
  of  elaborated-type-specifier  that  declares  a  class-name or friend
  class since it can be construed as referring to the definition of  the
  class.  Thus, in any elaborated-type-specifier, the enum keyword shall
  be used to refer to an enumeration (_dcl.enum_), the  union  class-key
  shall  be  used to refer to a union (_class_), and either the class or
  struct class-key shall be used to refer to a class (_class_)  declared
  using the class or struct class-key.


  7.1.3  The typedef specifier                             [dcl.typedef]
4 A typedef-name that names a class is a class-name (_class.name_).  The
  typedef-name  shall not be used after a class, struct, or union prefix
  and not in the names for constructors and destructors within the class
  declaration itself.


  14.13  Friends                                           [temp.friend]
3 A member of a class template may be declared to be a  friend.   [Exam-
  ple:
          template<class T> struct A {
                  struct B { };
                  void f();
          };

          class C {
                  template<class T> friend struct A<T>::B;
                  template<class T> friend void A<T>::f();
          };
   --end example]

---

Marc's snippet violates these rules in two ways:

1. Since a friend class declaration requires the class-key "class" and a
typedef-name may not be preceded by a class-key, a typedef-name is invalid
as the name of a friend class.

2. (more subtly) Since Y<T>::session is a typedef in the scope of Y<T> and
not a *member* of Y<T>, section 14.13 does apply. Even if "session" could
somehow be preceded with a class-key, it still would not qualify as a
template member friend.

Therefore, the compiler's refusal to compile is correct, although the
diagnostic is extremely misleading.

> > Reading the FAQs doesn't hurt . . .
>
> Nor does reading the posting before replying to it :-)

Sorry Marc, I owe you a huge apology. I did read your original post 3
times, and yet I still misunderstood it and underestimated the difficulty
of this problem. I hastily took you for a newbie to c.s.c++ and assumed
that your question was better suited to c.l.c++.mod. You know the old saw
about assumptions. Pardon me for jumping down your throat.

I hope that this explanation satisfies you better than my last misguided
attempt did. (If you're still angry with me, Marc, please note that my
email address has changed).
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~bradds


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: bradds@concentric.net (Bradd W. Szonye)
Date: 1996/09/24
Raw View
Roly Perera <rolyp@private.nethead.co.uk> wrote in article
<01bba8d9$448a3b20$2b8549c2@my-computer>...
> Bradd W. Szonye wrote:
> > Marc Girod wrote:
>
> > > template <class T> class Y {
> > >   public:
> > >     typedef T session;
> > > };
> > >
> > > class X {
> > >   template <class T> friend typename Y<T>::session;
> > >     void foo() {}
> > > };
> > >
> > > class Z: public Y<Z> {
> > >     void bar(X x) { x.foo(); }
> > > };
> > >
> > It has nothing to do with the typedef. Z simply does not have any
access to
> > X whatsoever (since it has no public members). X is a friend of Y, yes,
but
> > *not* of Z. Friendship is not inherited, to avoid opening up "access
holes"
> > through unanticipated derivation. If bar() were in  Y and inherited by
Z,
> > then Y::bar() could access x.foo(). Even so, an override of Z::bar()
> > *still* has no access to X.
>
> You've misunderstood the original posting.  X's templated friend
> declaration doesn't declare Y as a friend - it declares Y<T>::session as
a
> friend, which is a typedef defined within template class Y to be
equivalent
> to Y's type parameter.

You're right, I did misunderstand the problem. After much searching through
the working papers, I've come up with an alternative explanation. Bear with
me, there's several sections of the WP involved in this problem.


11.4 Friends

2 ... An elaborated-type-specifier shall be used in a friend declaration
for a class; see
_dcl.type.elab_ .(footnote 3) [Note: _dcl.type.elab_ further describes the
syntax
of friend class declarations.]

(3) The class-key of the elaborated-type-specifier is required.


  7.1.5.3  Elaborated type specifiers                    [dcl.type.elab]

1         elaborated-type-specifier:
                  class-key ::opt nested-name-specifieropt identifier
                  enum ::opt nested-name-specifieropt identifier
          class-key:
                  class
                  struct
                  union

2 If an elaborated-type-specifier is the sole constituent of a  declara-
  tion, the declaration is ill-formed unless it has one of the following
  forms:
  --      class-key identifier ;
3 --      friend class-key identifier ;
4 --      friend class-key ::identifier ;
          friend class-key nested-name-specifier identifier ;

6 The class-key or enum keyword present in the elaborated-type-specifier
  shall  agree  in  kind  with  the declaration to which the name in the
  elaborated-type-specifier refers.  This rule also applies to the  form
  of  elaborated-type-specifier  that  declares  a  class-name or friend
  class since it can be construed as referring to the definition of  the
  class.  Thus, in any elaborated-type-specifier, the enum keyword shall
  be used to refer to an enumeration (_dcl.enum_), the  union  class-key
  shall  be  used to refer to a union (_class_), and either the class or
  struct class-key shall be used to refer to a class (_class_)  declared
  using the class or struct class-key.


  7.1.3  The typedef specifier                             [dcl.typedef]
4 A typedef-name that names a class is a class-name (_class.name_).  The
  typedef-name  shall not be used after a class, struct, or union prefix
  and not in the names for constructors and destructors within the class
  declaration itself.


  14.13  Friends                                           [temp.friend]
3 A member of a class template may be declared to be a  friend.   [Exam-
  ple:
          template<class T> struct A {
                  struct B { };
                  void f();
          };

          class C {
                  template<class T> friend struct A<T>::B;
                  template<class T> friend void A<T>::f();
          };
   --end example]

---

Marc's snippet violates these rules in two ways:

1. Since a friend class declaration requires the class-key "class" and a
typedef-name may not be preceded by a class-key, a typedef-name is invalid
as the name of a friend class.

2. (more subtly) Since Y<T>::session is a typedef in the scope of Y<T> and
not a *member* of Y<T>, section 14.13 does apply. Even if "session" could
somehow be preceded with a class-key, it still would not qualify as a
template member friend.

Therefore, the compiler's refusal to compile is correct, although the
diagnostic is extremely misleading.

> > Reading the FAQs doesn't hurt . . .
>
> Nor does reading the posting before replying to it :-)

Sorry Marc, I owe you a huge apology. I did read your original post 3
times, and yet I still misunderstood it and underestimated the difficulty
of this problem. I hastily took you for a newbie to c.s.c++ and assumed
that your question was better suited to c.l.c++.mod. You know the old saw
about assumptions. Pardon me for jumping down your throat.

I hope that this explanation satisfies you better than my last misguided
attempt did. (If you're still angry with me, Marc, please note that my
email address has changed).
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~bradds
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: girod@dshp01.trs.ntc.nokia.com (Marc Girod)
Date: 1996/09/25
Raw View
Hello Bradd!

Thanks both for your apologies and for your good study of the draft.

>>>>> "BS" == Bradd W Szonye <bradds@concentric.net> writes:

BS> Marc's snippet violates these rules in two ways:

BS> 1. Since a friend class declaration requires the class-key "class" and a
BS> typedef-name may not be preceded by a class-key, a typedef-name is invalid
BS> as the name of a friend class.

Sounds like a killer...
Now, at least in the following case, a typedef _may_ be a friend:

template <class T> class Y {
    typedef T session;
  friend class session;
};

or may it? Invalidating it would break existing code; this has been
advocated as a work-around for years, for the next, equivalent, but
often not supported by existing compilers:

template <class T> class Y {
  friend class T;
};

And there, "class" could not be replaced with "typename"...
Now, is this really the intention, or is this is relief of
pre-typename versions of the draft, that should be updated?

BS> 2. (more subtly) Since Y<T>::session is a typedef in the scope of Y<T> and
BS> not a *member* of Y<T>, section 14.13 does apply. Even if "session" could
BS> somehow be preceded with a class-key, it still would not qualify as a
BS> template member friend.

I have always thought at a nested typedef as a member... My turn to
cite the draft, in a comment inside an example:

11   Member access control                    [class.access]
[ ... ]
5 [ ... ]
  [Example:
          class A {
              typedef int I;      // private member

That is, I take your point (1), but would reject (2).

And even for (1), I'd still like to hear further discussion, upon
whether this really is the last word or not.

Best Regards!
--
Marc Girod                                   Phone:  +358-0-511 27703
Nokia Telecommunications   P.O. Box 12       Fax:    +358-0-511 27432
Kilo RD 4                  FIN-02611 Espoo   marc.girod@ntc.nokia.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Bradd W. Szonye" <bradds@ix.netcom.com>
Date: 1996/09/20
Raw View
Marc Girod <girod@dshp01.trs.ntc.nokia.com> wrote in article
<1yrao1a0w4.fsf@dshp01.trs.ntc.nokia.com>...
> Could you please test it with other compilers, and/or argument about
> the legality/illegality of my code with respect to the draft standard.

Your code is illegal under current cplusplusses and the working papers
both.

> -1------------------------------
> template <class T> class Y {
>   public:
>     typedef T session;
> };
>
> class X {
>   template <class T> friend typename Y<T>::session;
>     void foo() {}
> };
>
> class Z: public Y<Z> {
>     void bar(X x) { x.foo(); }
> };
>
>       The test case appears to be invalid because it tries to declare a
>       typedef as a friend.  We lowered the priority because the compiler
>       still needs to diagnose that error.  Another defect will be
>       submitted for a modified test case which should be conforming.

It has nothing to do with the typedef. Z simply does not have any access to
X whatsoever (since it has no public members). X is a friend of Y, yes, but
*not* of Z. Friendship is not inherited, to avoid opening up "access holes"
through unanticipated derivation. If bar() were in  Y and inherited by Z,
then Y::bar() could access x.foo(). Even so, an override of Z::bar()
*still* has no access to X.

Please read your compiler's manuals (or, preferably, a good book such as
the ARM, C++ 2nd Ed, Lippman, etc.) carefully before asking questions like
this on a standards newsgroup. It's one thing to ask "Does this feature
belong in the language" and another to say "I don't know if this is right,
is it?" The former questions belong in comp.std.c++ and the latter in
comp.lang.c++.moderated. In general, requests for help are better suited to
the "lang" groups than the "std" groups. Reading the FAQs doesn't hurt
either.

I'm surprised there was no comment from the moderators on this.
--
Bradd W. Szonye
bradds@ix.netcom.com
http://www.geocities.com/SouthBeach/2447


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: girod@dshp01.trs.ntc.nokia.com (Marc Girod)
Date: 1996/09/17
Raw View
Hello!

I reported the following failure (1) as an error. I don't quite understand
(or agree with) the answer I received (2).

Could you please test it with other compilers, and/or argument about
the legality/illegality of my code with respect to the draft standard.

Best Regards!

Marc

-1------------------------------
template <class T> class Y {
  public:
    typedef T session;
};

class X {
  template <class T> friend typename Y<T>::session;
    void foo() {}
};

class Z: public Y<Z> {
    void bar(X x) { x.foo(); }
};

The compiler objects:

Error 199: "foo.C", line 12 # "void Z::bar(X)" cannot access private member "void X::foo()".
        void bar(X x) { x.foo(); }
                        ^^^^^^^

However, Y<Z>::session is a friend of X, and a typedef for Z itself.

-2------------------------------

      Response:
      The test case appears to be invalid because it tries to declare a
      typedef as a friend.  We lowered the priority because the compiler
      still needs to diagnose that error.  Another defect will be
      submitted for a modified test case which should be conforming.

--------------------------------
--
Marc Girod                                   Phone:  +358-0-511 27703
Nokia Telecommunications   P.O. Box 12       Fax:    +358-0-511 27432
Kilo RD 4                  FIN-02611 Espoo   marc.girod@ntc.nokia.com


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]