Topic: friend class based on template argument


Author: chchen@efi.com (Jason Chen)
Date: 1998/10/25
Raw View
    Is it legal to declare a friend class based on a template argument
in a template ?  For example,

template <class T, class C> class Safe {
    friend class C;
private:
    T secret;
}

class SafeOwner {
    int GetSecret(Safe<int,SafeOwner> *p) { return p->secret; }
};

     This code compiles on SGI CC 7.1, but not on VC++ 5.0 (complains
SafeOwner::GetSecret has no access to private member secret)  If I
change the class name of 'SafeOwner' to 'C', then it compiles on VC++ 5.0.
So it seems that VC++ doesn't treat the 'C' in friend class declaration
as the template argument but simply as a regular class name.  Is this
a VC++ bug or this is what the standard specifies ?
     In my case, I need to access the protected members of a class
which I can't modify to add a friend declaration:

class CantModify {
     // ....
protected:
     int data;
     void func();
     // ....
};

class Program {
private:
    CantModify obj;
public:
    int GetData() { return obj.data; }   // error !
};

     So, I use the following template to create a friend of CantModify
on demand:

template <class F> FriendOfCantModify: public CantModify {
    friend class F;
    FriendOfCantModify() : CantModify() {}
};

     Now I can use it to access protected members of CantModify:

class Program {
private:
    FriendOfCantModify<Program> obj;
public:
    int GetData() { return obj.data; }  // now works
};

     Is this an overuse of templates ?  Is there a better way to achieve
the same thing ?

-
--------------------------------------------------------------------------
|   Jason Chien-Hung Chen              <Jason.Chen@eng.efi.com>          |
|____ Electronics For Imaging, Inc. _____________________________________|
---
[ 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: huynh@anubisinc.com
Date: 1998/10/26
Raw View
In article <70r523$ffc@masters0.InterNex.Net>,
  chchen@efi.com (Jason Chen) wrote:
>     Is it legal to declare a friend class based on a template argument
> in a template ?  For example,
>
No. See 7.1.5.3. (2) [dcl.type.elab]

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ 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: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1998/10/26
Raw View
On 25 Oct 1998 20:06:17 -0500, Jason Chen <chchen@efi.com> wrote:

>    Is it legal to declare a friend class based on a template argument
>in a template ?  For example,

No.

[ 7.1.5.3.  Elaborated type specifiers ]

2  3.4.4 describes how name lookup proceeds for the identifier in an
   elaborated type specifier.  If the identifier resolves to a class-name
   or enum-name, the elaborated type specifier introduces it into the
   declaration the same way a simple type specifier introduces its type
   name.  If the identifier resolves to a typedef name or template type
   parameter, the elaborated type specifier is ill-formed.  [Note: this
   implies that, within a class template with a template type parameter
   T, the declaration
       friend class T;
   is ill-formed.]  If name lookup does not find a declaration for the
   name, the elaborated type specifier is ill-formed unless it is of the
   simple form class-key identifier in which case the identifier is
   declared as described in 3.3.1.


A template class definition is supposed to introduce only one thing
into the namespace: namely, the class.  Friend functions and friend
classes are not to be introduced into the namespace.

template <class T>
class X { friend T operator+(T,T); public: X(); };

struct s { };

X<s> x; // X<s> is instantiated, X<s>::X() is instantiated
// note: this is not instantiated:  s operator+(s,s)


>template <class T, class C> class Safe {
>    friend class C;
>private:
>    T secret;
>}

This is ill formed.


>class SafeOwner {
>    int GetSecret(Safe<int,SafeOwner> *p) { return p->secret; }
>};

-----

>     This code compiles on SGI CC 7.1, but not on VC++ 5.0 (complains
>SafeOwner::GetSecret has no access to private member secret)  If I
>change the class name of 'SafeOwner' to 'C', then it compiles on VC++ 5.0.
>So it seems that VC++ doesn't treat the 'C' in friend class declaration
>as the template argument but simply as a regular class name.  Is this
>a VC++ bug or this is what the standard specifies ?

Using como 4.2.38

"u.c", line 2: warning: template parameter C may not be used in an elaborated
          type specifier
      friend class C;
                   ^

"u.c", line 2: warning: template parameter C may not be used in an elaborated
          type specifier
      friend class C;
                   ^
          detected during instantiation of class
                    "Safe<T, C> [with T=int, C=SafeOwner]" at line 8


-----

>     In my case, I need to access the protected members of a class
>which I can't modify to add a friend declaration:

First off, avoid protected variables.  This needs repeating: avoid
protected variables.  Of course, sometimes you may have to use protected
variables.  In these cases, the class with the protected variable has
to be very simple -- preferably, only one data member in this class.
Protected functions are ok and often good design.  The problem with
protected variables is that eliminate the numerous advantages of
encapsulation: derived classes can access these variables just as if
they were public.


>     So, I use the following template to create a friend of CantModify
>on demand:
>
>template <class F> FriendOfCantModify: public CantModify {
>    friend class F;
>    FriendOfCantModify() : CantModify() {}
>};
>
>     Now I can use it to access protected members of CantModify:

I guess this is another reason why "friend class typename" is not
allowed.  Allowing it would let you get at the protected variables
and functions of class X, whereas by design, these entities are
supposed to be (partially) encapsulated.

-----

>     Is this an overuse of templates ?  Is there a better way to achieve
>the same thing ?

You can use still use templates, but in a more safe way.  It won't
apply to you, though, because your class CantModify has already been
written.


template <class Implementation>

/* class Implementation must have:
   a typedef "value_type"
   a variable "value" of type value_type
   a ctor "Implementation(value_type)"
   suitable friend declarations so that class Something can see
   "value_type" and "value"
 */

class Something : protected Implementation
{
     public:
          Something(value_type value) : Implementation(value) { }
          value_type get() const { return value; }
          friend class Goofy;
};


class MyImplementation
{
     typedef int value_type;
     value_type value;
     MyImplementation(value_type value_) : value(value_) { }

     friend class Something<MyImplementation>;
     // nofriend class Goofy;
};


Note that because MyImplementation::value and so on are private, and
because the inheritance Implementation==>Something is private or
protected, class Something inherits these members as super-private
members.  So class Goofy can't get at these variables, despite the fact
that it is a friend of class Something<T>.

The inheritance Implementation==>Something is protected so that classes
derived from class Something can access the concept of the base type
class Implementation.  Of course, class MyImplementation still needs to
be a friend to class Something<MyImplementation> and to the class derived
from Something<MyImplementation>.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ 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              ]