C++ template-based friend operators

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16 describes two ways of solving the "call to non-template" error. This error gets thrown when one defines a template class with some friend operator(s) declared in a natural manner, not thinking that declaring the template friend(s) like this will resolve the method into a non-template one. I find the first method of pre-declaring the operator to be tiresome and the second i say it can make the class definition unreadable if the operator definition is complex. I'm going to choose a third way of defining template friends:




template <typename T>
class C
{
  template <typename T1> friend istream& operator>>(istream &, C<T1>&);
}

altho this can be a little bit hard to understand at first sight because of different template parameter name


update: example for jamie



#include <iostream>

using namespace std;

//we define 
//the ostream operator the parashift's way 
//and the istream operator deadloop's way
  
  
//ostream operator related code
template<typename T> class A;
template<typename T> ostream& operator<< (ostream &os, const A<T>& a) throw();
//for istream we don't need to predeclare anything

template<typename T>
class A
{
public:
  A();
  template <typename T1> A(T1 value) throw();
  virtual ~A();
  //this is deadloop's istream operator, i don't need to convince the
  //compiler of anything
  template <typename T1> friend istream& operator>> (istream &is, A<T1>& a) throw();
  //and the parashift's way
  friend ostream& operator<< <> (ostream &os, const A<T>& si) throw();
private: 
  T data;
};

template <typename T> A<T>::A() {}
template <typename T> A<T>::~A() {}
template <typename T> istream& operator>> (istream &is, A<T> &a) throw()
  is>>a.data;
  
template <typename T> ostream& operator<< (ostream &os, const A<T>& a) throw()

{
  return os<<a.data;
}

int main(int argc, char **argv)
{
  A<int> ob;
  cout<<"enter an integer for A<int>: ";
  cin >>ob;
  cout << "object's data is: " << ob << endl;
  return 0;
}



3 comments:

  1. doesn't work for me ... i get error: `std::ostream& operator>>(std::ostream&)' must take exactly two arguments. :-( i'd love to see an elegant way of friend'ing a ostream operator in a template class that compiles without doing it outside the class.

    ReplyDelete
  2. okay, my bad ... i reviewed the code and found i forgot to comma separate the parameters ... still doesn't compile. i get "undefined reference to `std::basic_ostream >& operator<< , std::allocator > >(std::basic_ostream >&, set, std::allocator > >&)'
    collect2: ld returned 1 exit status"


    called like this in main():

    set s;
    s.insert("alpha");

    std::cout << s;

    arg!

    ReplyDelete
  3. sup jamie,

    i didn't expect any comments on my posts. sorry for not answering.
    i updated the post with an example for you.

    cheers,

    ReplyDelete