Friend functions and template classes

Discussion in 'C++' started by Adam Parkin, Apr 22, 2004.

  1. Adam Parkin

    Adam Parkin Guest

    Hello, all I'm having a problem with friend functions in a templatized Queue
    class I'm writing using linked lists. The problem is that I can't get the
    friend function to be able to access private data from the class. Here's
    the gist of the code:

    template <class T>
    struct NodeType
    {
    T data;
    NodeType<T> * link;
    };

    template <class T>
    class Queue1
    {
    friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    // some public methods & stuff here
    private:
    NodeType <T> * head;
    NodeType <T> * tail;
    };

    template <class T>
    ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs)
    {
    NodeType <T> * pIterator = rhs.tail;
    return &lhs;
    }

    The problem I get is that in the operator<< function my compiler (Visual C++
    6) is reporting:

    'tail' : cannot access private member declared in class 'Queue1<char>'

    (this is of course using a driver program that declares a Queue1<char>
    object).

    Any suggestions would be appreciated.

    Adam
     
    Adam Parkin, Apr 22, 2004
    #1
    1. Advertising

  2. Adam Parkin wrote:
    >

    [snip]
    >
    > template <class T>
    > class Queue1
    > {
    > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    > // some public methods & stuff here
    > private:
    > NodeType <T> * head;
    > NodeType <T> * tail;
    > };
    >
    > template <class T>
    > ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs)
    > {
    > NodeType <T> * pIterator = rhs.tail;
    > return &lhs;
    > }


    As Victor said, changing
    friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    to
    friend ostream & operator<< <> (ostream & lhs, const Queue1 <T> & rhs);

    (you can write <> instead of <T> here) would solve the problem with the
    right compiler. Here is why: your definition of operator<< is a function
    template; its friend declaration, if unqualified, must be a template-id
    (just what you probably meant to do).

    >
    > Any suggestions would be appreciated.


    0. Get a better compiler.

    There are a couple of alternatives that you could try as well.

    1. Remember,
    friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);

    is a declaration of a function, not a function template, despite the <T>
    in the argument list. That means that the compiler will need a corresponding
    definition. Replace your definition of operator<< with the following
    (but keep your original friend declaration):

    ostream & operator<< (ostream & lhs, const Queue1 <char> & rhs)
    {
    NodeType <char> * pIterator = rhs.tail;
    return lhs;
    }

    Note that this is not a template specialisation. I wouldn't like doing it
    this way, but it is still standard, and maybe VC++6 will accept it.


    2. Finally, you may try the following: qualify the declaration of the friend
    operator<< with :: and predeclare it (rules are different for qualified names
    in this case):

    template <class T>
    class Queue1;

    template <class T>
    ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);

    template <class T>
    class Queue1
    {
    friend ostream & ::eek:perator<< <> (ostream & lhs, const Queue1 <T> & rhs);
    // some public methods & stuff here
    private:
    NodeType <T> * head;
    NodeType <T> * tail;
    };


    Denis
     
    Denis Remezov, Apr 23, 2004
    #2
    1. Advertising

  3. "Adam Parkin" <> wrote...
    > Hello, all I'm having a problem with friend functions in a templatized

    Queue
    > class I'm writing using linked lists. The problem is that I can't get the
    > friend function to be able to access private data from the class. Here's
    > the gist of the code:
    >
    > template <class T>
    > struct NodeType
    > {
    > T data;
    > NodeType<T> * link;
    > };
    >



    I think you need to do a bit of a declaration dance. Put here:

    template<class T> class Queue1;
    template<class T> ostream& operator <<(ostream&, const Queue1<T>&);

    > template <class T>
    > class Queue1
    > {
    > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);


    Change this to

    friend ostream& operator<< <T>(ostream&, const Queue1&);

    > // some public methods & stuff here
    > private:
    > NodeType <T> * head;
    > NodeType <T> * tail;
    > };
    >
    > template <class T>
    > ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs)
    > {
    > NodeType <T> * pIterator = rhs.tail;
    > return &lhs;


    You probably meant

    return lhs;

    here. BTW, avoid typing your program directly into a posting.

    > }
    >
    > The problem I get is that in the operator<< function my compiler (Visual

    C++
    > 6) is reporting:
    >
    > 'tail' : cannot access private member declared in class 'Queue1<char>'
    >
    > (this is of course using a driver program that declares a Queue1<char>
    > object).


    ---------------------------------------------- This code
    #include <iostream>
    using namespace std;

    template <class T>
    struct NodeType
    {
    T data;
    NodeType<T> * link;
    };

    template<class T> class Queue1;
    template<class T> ostream& operator <<(ostream&, const Queue1<T>&);

    template <class T>
    class Queue1
    {
    friend ostream & operator<< <T>(ostream &, const Queue1&);
    // some public methods & stuff here
    private:
    NodeType <T> * head;
    NodeType <T> * tail;
    };

    template <class T>
    ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs)
    {
    NodeType <T> * pIterator = rhs.tail;
    return lhs;
    }

    int main()
    {
    Queue1<int> qi;
    cout << qi;
    return 0;
    }

    ----------------------------------------------
    compiles fine with Comeau and Intel. VC++ v6 refuses to compile it (due
    to its very poor template handling abilities). A quick solution to this
    would be a public member function

    ostream& print(ostream& out) const
    {
    // do what you need
    return out;
    }

    in the Queue1 template. The template output operator would call it:

    template<class T> ostream& operator << (ostream& os, const Queue1<T>& t)
    {
    return t.print(os);
    }
    ------------------------------- Full code that compiles with VC++
    #include <iostream>
    using namespace std;

    template <class T>
    struct NodeType
    {
    T data;
    NodeType<T> * link;
    };

    template <class T>
    class Queue1
    {
    public:
    ostream & print(ostream & out) const
    {
    NodeType<T> *pIt = tail;
    return out;
    }
    // some public methods & stuff here
    private:
    NodeType <T> * head;
    NodeType <T> * tail;
    };

    template<class T>
    ostream & operator<<(ostream & lhs, const Queue1<T> & rhs)
    {
    return rhs.print(lhs);
    }

    int main()
    {
    Queue1<int> qi;

    cout << qi;

    return 0;
    }
    ------------------------------------------------------------
    HTH

    Victor
     
    Victor Bazarov, Apr 23, 2004
    #3
  4. "Denis Remezov" <> wrote...
    > Adam Parkin wrote:
    > >

    > [snip]
    > >
    > > template <class T>
    > > class Queue1
    > > {
    > > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    > > // some public methods & stuff here
    > > private:
    > > NodeType <T> * head;
    > > NodeType <T> * tail;
    > > };
    > >
    > > template <class T>
    > > ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs)
    > > {
    > > NodeType <T> * pIterator = rhs.tail;
    > > return &lhs;
    > > }

    >
    > As Victor said, changing
    > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    > to
    > friend ostream & operator<< <> (ostream & lhs, const Queue1 <T> & rhs);
    >
    > (you can write <> instead of <T> here) would solve the problem with the
    > right compiler. Here is why: your definition of operator<< is a function
    > template; its friend declaration, if unqualified, must be a template-id
    > (just what you probably meant to do).
    >
    > >
    > > Any suggestions would be appreciated.

    >
    > 0. Get a better compiler.
    >
    > There are a couple of alternatives that you could try as well.
    >
    > 1. Remember,
    > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    >
    > is a declaration of a function, not a function template, despite the <T>
    > in the argument list. That means that the compiler will need a

    corresponding
    > definition. Replace your definition of operator<< with the following
    > (but keep your original friend declaration):
    >
    > ostream & operator<< (ostream & lhs, const Queue1 <char> & rhs)
    > {
    > NodeType <char> * pIterator = rhs.tail;
    > return lhs;
    > }
    >
    > Note that this is not a template specialisation. I wouldn't like doing it
    > this way, but it is still standard, and maybe VC++6 will accept it.
    >
    >
    > 2. Finally, you may try the following: qualify the declaration of the

    friend
    > operator<< with :: and predeclare it (rules are different for qualified

    names
    > in this case):
    >
    > template <class T>
    > class Queue1;
    >
    > template <class T>
    > ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    >
    > template <class T>
    > class Queue1
    > {
    > friend ostream & ::eek:perator<< <> (ostream & lhs, const Queue1 <T> & rhs);


    VC++ chokes on this. I gave a solution, and of course, your option 0
    is just fine too.

    Victor

    > // some public methods & stuff here
    > private:
    > NodeType <T> * head;
    > NodeType <T> * tail;
    > };
    >
    >
    > Denis
     
    Victor Bazarov, Apr 23, 2004
    #4
  5. Adam Parkin

    Adam Parkin Guest

    "Denis Remezov" <> wrote in
    message news:...
    > As Victor said, changing
    > friend ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);
    > to
    > friend ostream & operator<< <> (ostream & lhs, const Queue1 <T> & rhs);
    >
    > (you can write <> instead of <T> here) would solve the problem with the
    > right compiler.


    And of course VC6 is not the right compiler, as this doesn't work.

    > > Any suggestions would be appreciated.

    >
    > 0. Get a better compiler.


    LOL, thanks. :p

    > is a declaration of a function, not a function template, despite the <T>
    > in the argument list. That means that the compiler will need a

    corresponding
    > definition. Replace your definition of operator<< with the following
    > (but keep your original friend declaration):
    >
    > ostream & operator<< (ostream & lhs, const Queue1 <char> & rhs)
    > {


    Hehe, funny enough, VC6 reports this as "binary '<<' : no operator defined
    which takes a right-hand operand of type 'class Queue1<char>' (or there is
    no acceptable conversion)", even though I've explicitly included the <char>
    in my function definition.

    >
    > 2. Finally, you may try the following: qualify the declaration of the

    friend
    > operator<< with :: and predeclare it (rules are different for qualified

    names
    > in this case):
    >
    > template <class T>
    > class Queue1;
    >
    > template <class T>
    > ostream & operator<< (ostream & lhs, const Queue1 <T> & rhs);


    Yeah, I actually found this code on a few websites, but no, it doesn't work
    under VC6 (or at least didn't for me). Thanks for the help.

    Adam
     
    Adam Parkin, Apr 23, 2004
    #5
  6. Adam Parkin

    Adam Parkin Guest

    Re: Friend functions and template classes - fixed!

    "Victor Bazarov" <> wrote in message
    news:c4_hc.4892$0u6.1057800@attbi_s03...
    > "Adam Parkin" <> wrote...
    > > Hello, all I'm having a problem with friend functions in a templatized

    > Queue
    > > class I'm writing using linked lists. The problem is that I can't get

    the
    > > friend function to be able to access private data from the class.

    Here's
    > > the gist of the code:

    >


    Okay, figured out the problem, although I'm not entirely sure why it caused
    a problem. My driver.cpp had:

    #include "queue1.h"
    #include <iostream>
    using namespace std;

    in it, and once I changed this to:

    #include "queue1.h"
    #include <iostream>
    using std::cout;
    using std::endl;

    Everything worked fine, as the access of the private data member in
    operator<< was now legal. Can somebody explain why changes in one module
    (the Queue1.h file) were affected the way they were by the driver.cpp file?
    Is it that there's something in the std namespace which conflicted with my
    Queue1 module?

    I suppose this is a lesson in don't be lazy, use scope resolution to be as
    precise as possible.

    Adam
     
    Adam Parkin, Apr 23, 2004
    #6
  7. Re: Friend functions and template classes - fixed!

    "Adam Parkin" <> wrote...
    > "Victor Bazarov" <> wrote in message
    > news:c4_hc.4892$0u6.1057800@attbi_s03...
    > > "Adam Parkin" <> wrote...
    > > > Hello, all I'm having a problem with friend functions in a templatized

    > > Queue
    > > > class I'm writing using linked lists. The problem is that I can't get

    > the
    > > > friend function to be able to access private data from the class.

    > Here's
    > > > the gist of the code:

    > >

    >
    > Okay, figured out the problem, although I'm not entirely sure why it

    caused
    > a problem. My driver.cpp had:
    >
    > #include "queue1.h"
    > #include <iostream>
    > using namespace std;
    >
    > in it, and once I changed this to:
    >
    > #include "queue1.h"
    > #include <iostream>
    > using std::cout;
    > using std::endl;
    >
    > Everything worked fine, as the access of the private data member in
    > operator<< was now legal. Can somebody explain why changes in one module
    > (the Queue1.h file) were affected the way they were by the driver.cpp

    file?
    > Is it that there's something in the std namespace which conflicted with my
    > Queue1 module?
    >
    > I suppose this is a lesson in don't be lazy, use scope resolution to be as
    > precise as possible.


    I don't have an answer to your question about the namespace and the
    effect of it for the code, but I recommend asking the same question
    in microsoft.public.vc.language. Of course, keep in mind that they
    have been enjoying VC++ .NET probably longer on average than we here,
    so they may be tempted to simply say, "it's fixed in v7.1, so get it
    and the problem will go away"...

    Victor
     
    Victor Bazarov, Apr 24, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jess
    Replies:
    1
    Views:
    297
    John Harrison
    May 20, 2007
  2. =?gb2312?B?wfXquw==?=
    Replies:
    10
    Views:
    710
    Victor Bazarov
    Aug 1, 2007
  3. mojmir
    Replies:
    3
    Views:
    350
    mojmir
    Sep 12, 2008
  4. A L
    Replies:
    1
    Views:
    527
    Alf P. Steinbach /Usenet
    Aug 25, 2010
  5. SunRaySon

    Friend functions or classes

    SunRaySon, Dec 2, 2007, in forum: Ruby
    Replies:
    4
    Views:
    142
    Ilan Berci
    Dec 3, 2007
Loading...

Share This Page