I would like to overload the << operator, to print out a class instance to the console like this:
std::cout << instance << std::endl;
I've found a solution here: https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx
But I cannot use it, because my class is templated:
template<typename T>
myClass {
//code...
};
Edit:
I get an error, if I try to define it inside the class body: it must take only one argument
Sure you can use the example, just adapt it for your template.
Instead of
ostream& operator<<(ostream& os, const Date& dt)
you would need
template<class T>
ostream& operator<<(ostream& os, const myClass<T>& dt)
You can try this (adapt it to your code):
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// write obj to stream
return os;
}
Related
I'd like to implement operator<< for my templated class so that it can print all the elements it contains to the given std::ostream&. The issue is that I can't seem to get it to recognize the function that I've defined.
The error I get is
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'Outer<int>::Inner')
os << inner << ", ";
~~~^~~~~~~~
Ideally I'd like not to have the function defined inline, but I can't even get it to work inline. In the code below you can see that I've commented out my attempt at defining it outside the class declaration. It produces the same error as above.
This question recommends making the operator a friend of the class. I've done that every way I can think of and it still doesn't work.
The code:
#include <iostream>
template<class T>
class Outer {
class Inner {
T item;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& inner) {
os << inner.item;
return os;
}
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
};
std::vector<Inner> inner_items;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& bar);
};
/*template<class T>
std::ostream& operator<<(std::ostream& os, const typename Outer<T>::Inner& bar) {
os << inner.item;
return os;
}*/
template<class T>
std::ostream& operator<<(std::ostream& os, const Outer<T> outer) {
for (typename Outer<T>::Inner inner : outer.inner_items) {
os << inner << ", ";
}
return os;
}
int main()
{
Outer<int> outer;
std::cout << outer;
}
Do not make the output operator for the nested types templates:
#include <iostream>
#include <vector>
template<class T>
class Outer {
class Inner {
T item;
friend std::ostream& operator<<(std::ostream& os, typename Outer<T>::Inner const& inner) {
os << inner.item;
return os;
}
friend std::ostream& operator<<(std::ostream& os, const Outer<T> outer);
};
template <typename T_>
friend std::ostream& operator<< (std::ostream&, Outer<T_> const&);
std::vector<Inner> inner_items;
};
template<class T>
std::ostream& operator<<(std::ostream& os, Outer<T> const& outer) {
for (typename Outer<T>::Inner const& inner : outer.inner_items) {
os << inner << ", ";
}
return os;
}
int main()
{
Outer<int> outer;
std::cout << outer;
}
There are a few const& sprinkled and a necessary friend declaration added, too.
You don't need (neither want) to templetize in Inner, just use the type:
class Outer {
class Inner {
T item;
friend std::ostream& operator<<(std::ostream& os, const Inner& inner) {
os << inner.item;
return os;
}
// ...
What you wrote above fails because you define a free function in Outer<T>::Inner which is operator<<(..). The second parameter is Outer<T_>::Inner and the compiler cannot go from Inner to the type in which it was defined.
I want to implement a template function using nested-types of a template-class.
I have just read here that it is better to implement operator << as non-member and non-friend function. Therefore I decided to move functions toStream() and tableToStream() outside MyClass:
template <typename T>
class MyClass
{
public:
typedef boost::dynamic_bitset<> BoolTable;
typedef std::vector<T> MsgTable;
private:
BoolTable b_;
MsgTable m_;
public:
const BoolTable& getB() const { return b_; }
const MsgTable & getM() const { return m_; }
std::ostream& toStream (std::ostream& os) const
{
os <<"Bool: "; tableToStream (os, getB()); os <<'\n';
os <<"Msg:"; tableToStream (os, getM()); os <<'\n';
return os;
}
template <typename TABLE>
std::ostream& tableToStream (std::ostream& os, const TABLE& table) const
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
};
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T> mc)
{
return mc.toStream(os);
}
It's easy to convert MyClass::toStream() into an operator << non-member and non-friend function:
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "; mc.tableToStream (os, mc.getB()); os <<'\n';
os <<"Msg:"; mc.tableToStream (os, mc.getM()); os <<'\n';
return os;
}
But I want to use solely operator << instead of calling MyClass::tableToStream():
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "<< mc.getB() <<'\n';
os <<"Msg:" << mc.getM() <<'\n';
return os;
}
For the function MyClass::tableToStream() I could use the following implementation, but this may mess the stream output because the function is too generic (any type can be TABLE).
template <typename TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
Therefore, I want to restrict to the nested types of MyClass. Below is one of my attempts to convert MyClass::tableToStream() into a standard operator << non-member and non-friend function:
template <typename T, typename MyClass<T>::TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
But the error is about typename MyClass<T>::TABLE.
Since you have clarified your question a lot, my first answer does not apply any more and I'll remove-edit it to give you something that might fit better:
Updated answer:
You want to constrain the template to accept only types that are typedeffed inside your MyClass template. Such constraints are usually achieved by application of SFINAE, especially by std::enable_if (or boost::enable_if, if your library lacks that part of C++11 support). Sadly, there is no traits like a is_typedeffed_inside that could be used for your case. It's even worse: there is no way to write such a trait just using the plain typedefs, since there is nothing special about being typedeffed inside a given class - the compiler has no way to determine (and is not interested in) if a given known type has some alias name for it somewhere.
But if your typedefs are just the ones you show in your question, I have good news for you: you need exactly two operator<< for that:
One for boost::dynamic_bitset<>, since that is the BoolTable for any MyClass instantiation.
Another one, templated, for std::vector<T>, since that is the MsgTable for each corresponding MyClass<T>.
The downside is, that with this templated operator<<, you'd be able to output any std::vector<FooBar>, even if FooBar is completely unrelated to any use of MyClass. But that holds for any other possible implementation of the proper operator<<'s - if there's no explicit restriction on the MSG parameter, there's no restriction on a FooBar making a std::vector<FooBar> a viable MyClass<MSG>::MsgTable.
My conclusion for your question: you wanted to have the operator<< for its convenient looks, since it is normally used for thet purpose. In your case, you can provide it for MyClass<MSG> objects, but there is no way to do so for the inner typedefs alone.
I'd implement it that way:
template <class MSG>
class MyClass {
/* ... */
public:
// instead of declaring op<< a friend, redirect to a method that has
// natural access to private members
std::ostream& printToStream(std::ostream& os) const
{
os << "Bool: ";
tableToStream (getB(), os);
os <<"\nMsg:";
tableToStream (getM(), os);
return os <<'\n';
}
private:
// make this one private so nobody can misuse it to print unrelated stuff
template <class Table>
static void tableToStream(Table const& table, std::ostream& os)
{
std::copy(begin(table), end(table), ostream_iterator(os, ", "));
}
};
template <typename MSG>
std::ostream& operator << (std::ostream& os, const MyClass<MSG>& mc)
{
return mc.printToStream(os);
}
Your original class is fine. It is true that if you want to have an operator << for writing to a stream that it should be a non-member non-friend function, like you have, but there is no reason that function can't call a public member function to do the work.
I finally found this similar question
In my case the solution is:
template <typename T>
std::ostream& operator << (std::ostream& os,
typename MyClass<T>::TABLE const& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
UPDATE: As #ArneMertz pointed out, the above function does not work.
Below is the complete code I have tested:
#include <ostream>
#include <boost/dynamic_bitset.hpp>
template <typename T>
class MyClass
{
public:
typedef boost::dynamic_bitset<> BoolTable;
typedef std::vector<T> MsgTable;
BoolTable b_;
MsgTable m_;
const BoolTable& getB() const { return b_; }
const MsgTable & getM() const { return m_; }
};
template <typename T>
std::ostream& operator << (std::ostream& os,
typename MyClass<T>::TABLE const& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "<< mc.getB() <<'\n'; // <-- this line is OK because it
os <<"Msg: "<< mc.getM() <<'\n'; //uses boost operator<<
return os;
}
and the main function:
#include <iostream>
int main()
{
MyClass<int> var;
var.b_.push_back(true);
var.b_.push_back(false);
var.b_.push_back(true);
var.m_.push_back(23);
var.m_.push_back(24);
var.m_.push_back(25);
std::cout << var;
}
I believe you are confusing something. The typename is just to be able to seperate it from the other template-parameters. Try to rename it to
template <typename OS, typename MSG, typename MSGTable>
OS& operator << (OS& os, const MSGTable& table) const{}
and then use it like an object.
See here.
class W
{
private:
long m_val1, m_val2;
public:
W(long& val1, long& val2):m_val1(val1), m_val2(val2) {}
template<class T>
friend std::ostream& operator<<(std::ostream& os, const T& w);
};
class X
{
private:
long m_val1, m_val2;
public:
X(const long& val1, long& val2):m_val1(val1), m_val2(val2) {}
template<class T>
friend std::ostream& operator<<(std::ostream& os, const T& x);
};
template<class T>
std::ostream& operator<<(std::ostream& os, const T& obj)
{
os << "m_val1: " << obj.m_val1 << ", m_val2: " << obj.m_val2 << endl;
}
It does NOT work. Can anyone point out what do I miss? Thanks.
In addition, this results in "error C2593: 'operation <<' is ambiguous" wherever "cout << "some string";" is used.
You have created an output operator that can be called for all types, when it's obvious it should only be able to be used for the W and X classes. You need to narrow the scope of the output operator function.
The compiler can deduce the template from the call. So when you call os << "m_val1: ", based on your template implementation, it creates
template<class T>
std::ostream& operator<<(std::ostream& os, const string& obj)
witch already exists. More info about template argument deduction in http://accu.org/index.php/journals/409
Okay I'm a little stuck on trying to overload the << operator for my template class. The requirement is that the << operator must call a void print function defined for this class.
Here is the important stuff from the template header:
template <class T>
class MyTemp {
public:
MyTemp(); //constructor
friend std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a);
void print(std::ostream& os, char ofc = ' ') const;
and here is my print function basically it's a vector and prints last element to first:
template <class T>
void Stack<T>::print(std::ostream& os, char ofc = ' ') const
{
for ( int i = (fixstack.size()-1); i >= 0 ; --i)
{
os << fixstack[i] << ofc;
}
}
and here is how I have the operator<< overloaded:
template <class T>
std::ostream& operator<< (std::ostream& os, const Stack<T>& a)
{
// So here I need to call the a.print() function
}
But I am receiving an "unresolved external symbol" error. So really I guess I have two issues. The first, is the way to fix the error above. Second, once that is fixed would I just call a.print(os) inside << overload? I know it needs to return an ostream though. Any help would be greatly appreciated!
The simplest thing to do would be to leave print public (as it is in your example), so the operator doesn't need to be a friend.
template <class T>
class MyTemp {
public:
void print(std::ostream& os, char ofc = ' ') const;
};
template <class T>
std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
If you do need it to be private, then you need to declare the correct template specialisation to be a friend - your friend declaration declares a non-template operator in the surrounding namespace, not a template. Unfortunately, to make a template a friend you need to declare it beforehand:
// Declare the templates first
template <class T> class MyTemp;
template <class T> std::ostream& operator<< (std::ostream&, const MyTemp<T>&);
template <class T>
class MyTemp {
public:
friend std::ostream& operator<< <>(std::ostream& os, const MyTemp<T>& a);
// With a template thingy here ^^
private:
void print(std::ostream& os, char ofc = ' ') const;
};
template <class T>
std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
Or you could define the operator inline:
template <class T>
class MyTemp {
public:
friend std::ostream& operator<<(std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
private:
void print(std::ostream& os, char ofc = ' ') const;
};
For your last question:
Second, once that is fixed would I just call a.print(os) inside << overload? I know it needs to return an ostream though.
It does indeed need to return an ostream - so just return the one that was passed in, as in my example code.
This error means there is an symbol which could not be recognized by the linker.on what variable are u getting this error
and also please check on stack as well because there is a std::stack class available.
As your print member function is public, there's no need to declare operator<< as friend.
Beware that you are using class Stack is your overload, and MyTemp above ...
Is there any way of creating a function that accepts any version of a given
template class?
e.g. this works:
ostream& operator << (ostream &out,const Vector<int>& vec);
but this doesn't:
ostream& operator << (ostream &out,const Vector& vec);
Is it possible to get the second line to work somehow for any version of vector?
e.g. vector<int> and vector<double> without having to write 2 separate functions?
Added to question:
I've made op<< a template function like you've suggested. In order to make it a friend function of the vector class I tried adding the following to the Vector class definition, but it didn't work:
friend ostream& operator << (ostream &out, const Vector<T>& vec);
any ideas what can be done to fix it?
Sure, make it a template function:
template <typename T>
ostream& operator << (ostream &out,const Vector<T>& vec);
template <class T>
ostream& operator << (ostream &out,const Vector<T>& vec);
As already pointed out something like this should work:
template <typename T>
ostream& operator << (ostream &out,const Vector<T>& vec) {
// body here
}
As for the friend requirement, that is most easily handled like this:
template <typename T>
ostream& operator << (ostream &out,const Vector<T>& vec) {
vec.print_on( out );
return out;
}
However, normally I would think of any output operator like this that requires access to the internals of the class to be showing you a mistake in your Vector class. It really only ought to need to use the public interface to do the display.
The other thing is that you might also want to template the output stream itself so that you can preserve its type:
template <typename O, typename C, typename T>
std::basic_ostream<O, C>& operator << (std::basic_ostream<O, C> &out,const Vector<T>& vec) {
vec.print_on( out );
return out;
}
The Vector's print_on can still use ostream.