Topic: Clarification on friends, templates, typedefs, and traits?


Author: wmm@fastdial.net
Date: 1999/09/09
Raw View
In article <7r4o4n$ioi$1@agate-ether.berkeley.edu>,
  ejr@lotus.CS.Berkeley.EDU (Edward Jason Riedy) wrote:
>
> So 14.5.3 paragraph 9 states that ``[friend] declarations shall not
> declare partial specializations.''  May they refer to partial
> specializations?  In a closely related question, what is the
> relationship between typedefs and friend declarations?
>
> Questionable code:
> ====
> template <typename T, typename Ref, typename Ptr> class
_some_iterator;
> template <typename T, typename Ref, typename Ptr>
> struct _iterimpl_trait {
>   typedef void other_iterator;
> }
> template <typename T>
> struct _iterimpl_trait<T,T&,T*> {
>   typedef _some_iterator<T,const T&,const T*> other_iterator;
> };
> template <typename T>
> struct _iterimpl_trait<T,const T&, const T*> {
>   typedef _some_iterator<T,T&,T*> other_iterator;
> }
> template <typename T, typename Ref, typename Ptr>
> class _some_iterator {
>   friend class _iterimpl_trait<T,Ref,Ptr>::other_iterator;
>   /* Or?
>     typedef _iterimpl_trait<T,Ref,Ptr>::other_iterator other_iterator;
>     friend class other_iterator;
>   */
> };
> ====
>
> Ignoring some of the design choices here, is this ill-formed?

This is fine (modulo a couple of missing semicolons).  The EDG
compiler (version 2.42) agrees.

The typedef alternative you suggest in the comment would not be,
however -- you can't use a typedef name in an elaborated-type-
specifier (7.1.3p4).

> Related:  Is it an error for a class to declare itself as a friend?
> The opening of 11.4 doesn't seem to disallow it, but there's already
> a defect report on the opening.

The issue you mention is unrelated to this question.  As far as I
know, there's nothing to prohibit a class declaring itself as a
friend (although it's obviously redundant to do so).

> And there's a possible typo on p182 (208 of 776 in the pdf):  The
> pmi_B2 variable was probably meant to be pmi_D2.

Correct.  I'll add this to the issues list.

> Actually, in that example, how is access to B::j allowed?  Remove
> all references to D1 and D2 from the function, then move the
> definitions of D1 and D2 to another translation unit.  Why does
> this change the accessability of B::j?  I must be missing something
> obvious.

Access control is not obvious. :-)

In this case, what you're missing is the third bullet of 11.2p4,
which allows access to a protected member named in class N when
"the reference occurs in a member or friend of class N, or in a
member or friend of a class P derived from N, where M as a member
of P is private or protected."  In the example in 11.5p1, the
reference occurs in a friend of D2, which is derived from B, and
"j" is protected in D2, so the access is allowed.

And you're right, if D2 were removed from this compilation unit,
the access would not be permitted.
--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: ejr@lotus.CS.Berkeley.EDU (Edward Jason Riedy)
Date: 1999/09/08
Raw View
So 14.5.3 paragraph 9 states that ``[friend] declarations shall not
declare partial specializations.''  May they refer to partial
specializations?  In a closely related question, what is the
relationship between typedefs and friend declarations?

Questionable code:
====
template <typename T, typename Ref, typename Ptr> class _some_iterator;
template <typename T, typename Ref, typename Ptr>
struct _iterimpl_trait {
  typedef void other_iterator;
}
template <typename T>
struct _iterimpl_trait<T,T&,T*> {
  typedef _some_iterator<T,const T&,const T*> other_iterator;
};
template <typename T>
struct _iterimpl_trait<T,const T&, const T*> {
  typedef _some_iterator<T,T&,T*> other_iterator;
}
template <typename T, typename Ref, typename Ptr>
class _some_iterator {
  friend class _iterimpl_trait<T,Ref,Ptr>::other_iterator;
  /* Or?
    typedef _iterimpl_trait<T,Ref,Ptr>::other_iterator other_iterator;
    friend class other_iterator;
  */
};
====

Ignoring some of the design choices here, is this ill-formed?

The grammar seems to allow it, but the grammar's buggy.  I can't
see an obvious part of the standard that says something specific
here.  I'd expect to be asked to use typename rather than class,
but that doesn't work on the compiler I'm using (gcc 19990901,
with some bugs in this area already, but I want to know which are
compiler bugs and which are standard bugs).

Related:  Is it an error for a class to declare itself as a friend?
The opening of 11.4 doesn't seem to disallow it, but there's already
a defect report on the opening.

And there's a possible typo on p182 (208 of 776 in the pdf):  The
pmi_B2 variable was probably meant to be pmi_D2.

Actually, in that example, how is access to B::j allowed?  Remove
all references to D1 and D2 from the function, then move the
definitions of D1 and D2 to another translation unit.  Why does
this change the accessability of B::j?  I must be missing something
obvious.

Jason


[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]