ostream and nested template class problems
Hi everyone,
I experimented a bit with stream iterators following one of Danny's
"10-Minute-Solutions". Great stuff, but I hit a problem when I tried
to use the same techique for a nested class template. I attach the code
if you want to reproduce the problem. The thing that puzzles me is, that
I can manually iterate through the list of nested class objects and use
the stream operator, but cannot compile when I try to use the std::copy()
algorithm. Am I missing anything here or is this a (known?) deficiancy of
STL or more likely Microsofts implementation of it?
Any tips welcome...
Thanks,
Dieter
// OStrTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <iterator>
using namespace std;
template <class X>
class my_class
{
public:
class sub
{
string str;
public:
sub(string s)
: str(s)
{
}
friend ostream& operator << (ostream& os, const sub& s);
friend class my_class<X>;
};
private:
X member1;
X member2;
vector<sub> strs;
public:
my_class(X m1 = 0,X m2 = 0)
{
member1 = m1;
member2 = m2;
strs.push_back(string("str1"));
strs.push_back(string("str2"));
strs.push_back(string("str3"));
strs.push_back(string("str4"));
}
friend ostream& operator << (ostream& os, my_class<X>& mcl);
};
template <class X>
ostream& operator << (ostream& os, const my_class<X>::sub& s)
{
os << " - " << s.str << endl;
return os;
}
template <class X>
ostream& operator << (ostream& os, my_class<X>& mcl)
{
os << "(" << mcl.member1 << "," << mcl.member2 << ")" << endl;
for(vector<my_class<X>::sub>::iterator it=mcl.strs.begin(); it != mcl.strs.end() ; it++)
cout << (*it);
//
// UNCOMMENTING THE NEXT LINE PRODUCES THE FOLLOWING ERROR:
//
// c:\program files\microsoft visual studio\vc98\include\iterator(203) :
// error C2679: binary '<<' : no operator defined which takes a right-hand operand
// of type 'const class my_class<int>::sub' (or there is no acceptable conversion)
// c:\program files\microsoft visual studio\vc98\include\iterator(203) :
// while compiling class-template member function
// 'class std::ostream_iterator<class my_class<int>::sub,char,struct std::char_traits<char> >
// &__thiscall std::ostream_iterator
// <class my_class<int>::sub,char,struct std::char_traits<char> >::operator =
// (const class my_class<int>::sub &)'
// This line produces the error
// std::copy(mcl.strs.begin(),mcl.strs.end(),ostream_iterator<my_class<X>::sub> (os, " "));
return os;
}
int main(int argc, char* argv[])
{
my_class<int> mcl1(3,5);
cout << mcl1 << endl;
my_class<double> mcl2(3.14159265,5.678);
cout << mcl2 << endl;
return 0;
}
[3587 byte] By [
drkybelk] at [2007-11-11 7:53:57]

# 1 Re: ostream and nested template class problems
Your code has a few tiny bugs that have to do with friend templates. I also fixed a few stylistic gaffes such as passing a string argument by value (instead by reference to const) and most importantly: moved the friend functions' definition into the relecant classes. You also missed some typenames and qualified names that are often needed to convince the compiler that your code is kosher. Here's the modified version. It works perfectly. You alos want to read my latest 10 Minute Solution about friend declarations. It's exactly what you need;)
http://www.dev-archive.com/cplus/10MinuteSolution/30302/
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
using namespace std;
template <class X>
class my_class
{
public:
class sub
{
string str;
public:
sub(const string & s)
: str(s)
{
}
friend ostream& operator << (ostream& os, const typename my_class<X>::sub& s)
{
os << " - " << s.str << endl;
return os;
}
}; //sub
private:
X member1;
X member2;
vector<sub> strs;
public:
my_class(X m1 = 0,X m2 = 0)
{
member1 = m1;
member2 = m2;
strs.push_back(string("str1"));
strs.push_back(string("str2"));
strs.push_back(string("str3"));
strs.push_back(string("str4"));
}
friend ostream& operator << (ostream& os, my_class<X>& mcl)
{
os << "(" << mcl.member1 << "," << mcl.member2 << ")" << endl;
for(vector<my_class<X>::sub>::iterator it=mcl.strs.begin(); it != mcl.strs.end() ; it++)
cout << (*it);
std::copy(mcl.strs.begin(),mcl.strs.end(), ostream_iterator<typename my_class<X>::sub> (os, " "));
return os;
}
};
int main(int argc, char* argv[])
{
my_class<int> mcl1(3,5);
cout << mcl1;
my_class<double> mcl2(3.14159265,5.678);
cout << mcl2 << endl;
return 0;
}
Danny at 2007-11-11 21:01:52 >

# 2 Re: ostream and nested template class problems
Thanks Danny,
but on my compiler I still get an error. This time it is more explicit in the way that it tells me
c:\other development\stlalgorithmtest\ostrtest\ostrtest.cpp(18) : error C2027: use of undefined type 'my_class<int>'
c:\other development\stlalgorithmtest\ostrtest\ostrtest.cpp(52) : see reference to class template instantiation 'my_class<int>' being compiled
c:\other development\stlalgorithmtest\ostrtest\ostrtest.cpp(18) : error C2027: use of undefined type 'my_class<double>'
c:\other development\stlalgorithmtest\ostrtest\ostrtest.cpp(54) : see reference to class template instantiation 'my_class<double>' being compiled
The error is on the following line:
friend ostream& operator << (ostream& os, const typename my_class<X>::sub& s)
It seems to still not recognize the type. I tried forward declarations, but they do not solve the problem either. (BTW: I copied/pasted your code).
Thanks for the link, I didn't know that you can implement a friend inside a class. That's useful...
Cheers,
D