Topic: problem with template friend ?


Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 7 May 92 19:37:54 GMT
Raw View

rmartin@willing.Rational.COM (Bob Martin) writes

 > Pardon my ignorance of templates.  I can see that this will work, but
 > it bothers me that you have defined a template whose implementation is
 > specific to stack<class, int>, but whose declaration appears to
 > announce that it can handle any class at all.
 >
 > What am I missing here????

Nothing. Sorry. My mistake.




Author: herman@cs.kuleuven.ac.be (Herman Moons)
Date: Mon, 4 May 1992 11:09:50 GMT
Raw View
I'm having some problems with interpreting the definition of templates
as given in the ARM.

question 1:
-----------
is it possible to specify default values for non-type template arguments ?

   e.g. template <class T, int size=100> class Stack { ... };



Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 5 May 92 09:57:10 GMT
Raw View

herman@cs.kuleuven.ac.be (Herman Moons) writes:

I'm having some problems with interpreting the definition of templates
as given in the ARM.

question 1:
-----------
is it possible to specify default values for non-type template arguments ?

   e.g. template <class T, int size=100> class Stack { ... };

>From the syntax specified in ARM p.342 I deduce that it might be possible.
However, the two compilers with template support I have access two differ
in this respect

   AT&T cfront 3.01 : does not accept default arguments
   Borland C++ 3.0  : considers default arguments ok

***> BC++ is right.

question 2:
-----------
How can you specify friend functions for a template class with non-type
arguments ? According to ARM p.347, function templates may use only type
arguments.
***> You are right.

This would mean that I cannot define friend functions for class templates,
as indicated in the example below:

   |  template <class T, int sz>
   |  class stack {
   |      friend ostream& operator<< (ostream& os, stack<T,sz>);
   |  public:
   |      stack () { index = 0; }
   |      void push (T elem) { tab[index++] = elem; }
   |      T pop (void) { return tab[--index]; }
   |  private:
   |      T tab[sz];
   |      int index;
   |  };
   |
   |
   |  // The following is illegal according to ARM, but is really what
   |  // is needed
   |  template <class T, int sz>
   |  ostream& operator<< (ostream& os, stack<T,sz> st)
   |  {
   |      for (int i=0; i<st.index; i++)
   |          os << st.tab[i] << endl;
   |      return os;
   |  }

Correct me if I'm wrong, but it seems to me that one cannot specify (in
generic terms) the type of the stack in the friend function. Is there a
work-around for this kind of friend functions (after all, overloading the
output operator is not that special, and I would expect that it should be
possible to do this).
***> This conclusion is wrong. Look at your friend declaration and consider
 what the matching function should look like. Then try this:

#include<iostream.h>
     template <class T, int sz>
    class stack {
         friend ostream& operator<< (ostream& os, stack<T,sz>);
     public:
         stack () { index = 0; }
         void push (T elem) { tab[index++] = elem; }
         T pop (void) { return tab[--index]; }
     private:
         T tab[sz];
         int index;
     };

     template <class T>
     ostream& operator<< (ostream& os, T st)
     {
         for (int i=0; i<st.index; i++)
           os << st.tab[i] << endl;
         return os;
     }

It works.




Author: rmartin@willing.Rational.COM (Bob Martin)
Date: 6 May 92 21:46:30 GMT
Raw View
bs@alice.att.com (Bjarne Stroustrup) writes:

>#include<iostream.h>
>     template <class T, int sz>
>    class stack {
>         friend ostream& operator<< (ostream& os, stack<T,sz>);
>     public:
>         stack () { index = 0; }
>         void push (T elem) { tab[index++] = elem; }
>         T pop (void) { return tab[--index]; }
>     private:
>         T tab[sz];
>         int index;
>     };
>
>     template <class T>
>     ostream& operator<< (ostream& os, T st)
>     {
>         for (int i=0; i<st.index; i++)
>           os << st.tab[i] << endl;
>         return os;
>     }

>It works.

Pardon my ignorance of templates.  I can see that this will work, but
it bothers me that you have defined a template whose implementation is
specific to stack<class, int>, but whose declaration appears to
announce that it can handle any class at all.

   template <class T> ostream operator<< (ostream& os, T st);

What prevents this declaration from being invoked when I do the
following?

#include <iostream.h>
#include "x.h" /* declaration of class X */
#include "stack.h" /* from the example above */

X myX;
stack<int, 100> myStack;

cout << myStack;
cout << myX;

If we assume that x.h does not declare a valid operator<< for X then
won't the template in stack.h get used to generate an invalid instance
of operator<< for X??

What am I missing here????
--
+---Robert C. Martin---+-RRR---CCC-M-----M-| R.C.M. Consulting         |
| rmartin@rational.com |-R--R-C----M-M-M-M-| C++/C/Unix Engineering    |
|     (Uncle Bob.)     |-RRR--C----M--M--M-| OOA/OOD/OOP Training      |
+----------------------+-R--R--CCC-M-----M-| Product Design & Devel.   |