How to implement a << interface in C++? - c++

I'm working on a tiny compiler, and I use boost::variant<bool, ClassA> infoto store the information of each node.
boost::variant will automatically call the correct << operator of a specific type when I call std::cout<< node.info;
However, since the built-in formatting function of ostream doesn't satisfy my requirement(print #t instead of 1 if node.info==true and print "string" instead of string), new types of bool/string should be introduced.
I want to implement a template class Wrapper<T>, which behaves just like T(because there are lots of old code) and provides the interface of <<.
At first, the following version was implemented:
template<typename T> class Wrapper : public T
{
public:
template<typename ... U> Wrapper(const U& ... a):T(a...) {}
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
This version works well for std::string, but when T=bool, since built-in types cannot be inherited, an error will raise.
My current workaround is to use partial specialization:
template<typename T, bool ISCLASS= std::is_class<T>::value> class Wrapper;
template<typename T> class Wrapper<T, false>
{
private:
T inner;
public:
template<typename ... U> Wrapper(const U& ... a): inner(a...) {}
//Wrap the operators (= + += ...)
template<typename U> Wrapper<T> operator !() { Wrapper<T> res(*this); res.inner=!res.inner; return res; }
operator T() const{ return inner; }
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
template<typename T> class Wrapper<T, true> : public T
{
public:
template<typename ... U> Wrapper(const U& ... a):T(a...) {}
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
Obviously it is not a perfect solution because I have to wrap every operators of bool or any other built-in types.
Any help would be appreciated.
Thanks.

Could we consider something simpler?
Create a simple wrapper, using reference or pointer.
template <class T>
struct MyFormattingWrapper
{
const T& nucleus;
};
And then a factory function for it.
template <class T>
MyFormattingWrapper<T> my_formatting(const T& n)
{
return MyFormattingWrapper<T>{ n };
}
And then, you can specialize the formatting for each type.
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<int>& w)
{
return o << "int:" << w.nucleus;
}
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<std::string>& w)
{
return o << "std::string:" << w.nucleus;
}
int main()
{
std::cout << my_formatting(123) << std::endl;
std::cout << my_formatting(std::string{ "abc" }) << std::endl;
}
Update:
C-string may be a special case. But it is not difficult.
struct MyFormattingWrapper_c_string
{
const char* const nucleus;
};
MyFormattingWrapper_c_string my_formatting(const char* n)
{
return MyFormattingWrapper_c_string{ n };
}
MyFormattingWrapper_c_string my_formatting(char* n)
{
return MyFormattingWrapper_c_string{ n };
}
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper_c_string& w)
{
return o << "c-string:" << w.nucleus;
}

Nicky C's answer is great, but has an issue with partial specialization of functions not being OK. This means you can't produce a version that works on general vectors like this:
template<typename T>
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<std::vector<T>>& vec)
{
o << "vec:[ "
for(auto v : vec) {
o<<my_formatting(v);
o<<" ";
}
return o<<"]"
}
You can get around this by putting the core of the specialized output into the MyFormattingWrapper classes and having only one operator<<
// The default one
template <class T> struct MyFormattingWrapper {
const T& nucleus;
ostream& output(ostream & os) {
return os<<nucleus;
}
};
// Specialized for string
template <> struct MyFormattingWrapper<std::string> {
const std::string& nucleus;
ostream& output(ostream & os) {
return os<<"string:"<<nucleus;
}
};
// Specialized for vector
template <class T> struct MyFormattingWrapper<std::vector<T>> {
const std::vector<T>& nucleus;
ostream& output(ostream & os) {
os<<"vec:[";
for(auto & v: nucleus) {
os<<my_formatting(v)<<" ";
}
return os<<"]";
}
};
// Now there's just one of these, so partial template
// specialization doesn't cause us any problems
template<typename T>
std::ostream& operator << (std::ostream& os, const MyFormattingWrapper<T>& w) {
return w.output(os);
}

Perhaps I better make the follow-up regarding boost::variant another answer.
Firstly, learning from #MichaelAnderson, and considering the interoperability with boost::variant, I would like to improve the design of the wrapper. We add a constructor to enable type conversion for from the nucleus type to the wrapper type.
template <class T>
class MyFormatting;
template <class T>
MyFormatting<T> my_formatting(const T& n)
{
return MyFormatting <T>{n};
}
// int
template <>
class MyFormatting<int>
{
private:
const int& nucleus;
public:
MyFormatting(const int& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "int:" << w.nucleus;
}
};
// std::string
template <>
class MyFormatting<std::string>
{
private:
const std::string& nucleus;
public:
MyFormatting(const std::string& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "std::string:" << w.nucleus;
}
};
// c-string
template <>
class MyFormatting<char*>
{
private:
const char* nucleus;
public:
MyFormatting(const char* n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "c-string:" << w.nucleus;
}
};
MyFormatting<char*> my_formatting(const char* n)
{
return MyFormatting<char*>{n};
}
// std::vector
template <class T>
class MyFormatting<std::vector<T>>
{
private:
const std::vector<T>& nucleus;
public:
MyFormatting(const std::vector<T>& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
os << "std::vector:[";
for (const auto& x : w.nucleus)
{
os << x << " ";
}
os << "]";
return os;
}
};
Next, let's use the wrapper with boost::variant. The constructor of the wrapper enables conversion between variant of nuclues types to variant of the wrappers.
boost::variant<int, std::string> var_int = 50;
boost::variant<int, std::string> var_str = "fifty";
boost::variant<MyFormatting<int>, MyFormatting<std::string>> var_fmt_int = var_int;
boost::variant<MyFormatting<int>, MyFormatting<std::string>> var_fmt_str = var_str;
std::cout << var_int << " " << var_str << std::endl;
std::cout << var_fmt_int << " " << var_fmt_str << std::endl;
But boost::variant<MyFormatting<int>, MyFormatting<std::string>> spells too long. We can make it shorter.
template <class... T>
using Variant_Formatting_t = boost::variant < MyFormatting<T>... > ;
std::cout << Variant_Formatting_t<int, std::string>{var_int} << " " << Variant_Formatting_t<int, std::string>{var_str} << std::endl;
Since boost::variant use macro-template metaprogramming to emulate variadic template instead of using C++11 variadic template, I cannot make it cleaner using type deduction. This is the furthest I can get to.

Related

Wierd stuff happens when overloading operator<< with a class template

Here's the functionality I am expecting to achieve:
darray<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
std::cout << a << std::endl; // displays: {1, 2, 3}
My implementation:
template <typename T>
class darray
{
private:
long m_capacity;
long m_size;
T* m_data;
void resize();
public:
// constructors & destructors
darray();
// operations
void push_back(T);
std::ostream& print(std::ostream&) const;
template<typename U> friend std::ostream& operator<<(std::ostream& os, U const& ar);
};
template<typename T>
std::ostream& darray<T>::print(std::ostream& os) const
{
os << "{ ";
for (size_t i = 0; i < m_size; i++)
{
os << m_data[i] << ", ";
if ( i == m_size - 1 )
os << m_data[i];
}
os << " }\n";
return arr;
}
template<typename U>
std::ostream& operator<<(std::ostream& os, U const& obj)
{
return obj.print(os);
}
produces an error:
error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘const char [66]’)
But, when I change the parameter of operator<< to accept a darray<U> instead , it works fine:
template<typename U>
std::ostream& operator<<(std::ostream& os, darray<U> const& obj)
{
return obj.print(os);
}
What am I missing here?
Update:
I also tried doing this, changing the parameter to darray<U> type in the definition and the implementation, but it still produces the same error:
template <typename T>
class darray
{
private:
long m_capacity;
long m_size;
T* m_data;
void resize();
public:
// constructors & destructors
darray();
// operations
void push_back(T);
std::ostream& print(std::ostream&) const;
template<typename U> friend std::ostream& operator<<(std::ostream& os, darray<U> const& ar);
};
template<typename T>
std::ostream& darray<T>::print(std::ostream& os) const
{
os << "{ ";
for (size_t i = 0; i < m_size; i++)
{
os << m_data[i] << ", ";
if ( i == m_size - 1 )
os << m_data[i];
}
os << " }\n";
return os;
}
template<typename U>
std::ostream& operator<<(std::ostream& os, darray<U> const& obj)
{
return obj.print(os);
}
Friend functions in template classes have to be defined inside the class declaration. This is the only way I have found to have the friend function to correctly accept an instance of the templated class with the expected template.
So here I would write:
...
friend std::ostream& operator<<(std::ostream& os, darray<T> const& ar) {
ar.print(os);
return os;
}
...
But beware: your class contains a raw pointer to allocated memory which is probably deleted in the class destructor. Per the rule of five, you must explicitely declare (or delete) the copy/move constructors and assignment operators.
In your darray<T>::print function, if you change
os << m_data[i] << ", ";
to
os << m_data[i];
os << ", ";
then the compiler doesn't complain and it works fine. I don't know why.

How to override output operator (<<) as a function template outside a class template

I am reading Section 2.4 of the book "C++ tempalte, a complete guide".
I tried to override output operator (<<) as a function template outside the class template Stack<>.
Below is my code, but it doesn't work.
#include <iostream>
#include <string>
#include <vector>
template<class T>
class Stack
{
private:
std::vector<T> v;
public:
void push(T a);
void printOn(std::ostream & os) const;
template <typename U>
friend std::ostream& operator<< (std::ostream& out, const Stack<U> & s);
};
template<typename T>
std::ostream& operator<< (std::ostream out, const Stack<T> & s)
{
s.printOn(out);
return out;
}
template<class T>
void Stack<T>::push(T a)
{
v.push_back(a);
}
template<class T>
void Stack<T>::printOn(std::ostream & out) const
{
for(T const & vi : v)
{out << vi << " ";}
}
int main()
{
Stack<int> s1;
s1.push(12);
s1.push(34);
std::cout << s1;
}
You are just omitting the &, which makes the operator<< inside and outside the class have different function signatures, they are both valid for std::cout << s1, hence the ambiguity
template<typename T>
std::ostream& operator<< (std::ostream& out, const Stack<T> & s)
// ^
{
s.printOn(out);
return out;
}

How to overload ostream for a member struct of a templated class

I'm implementing a dictionary in C++ using a binary tree, each node in my tree has a key(int), item(string) and left and right child.
During this implementation, I overloaded the ostream operator for my BinaryTree class to print out the contents of the tree.
Additionally, I overloaded the ostream to work with Node pointers that would then print out the key and the item of that node.
This worked fine. However when I tried to then make the tree a template to work with any type for my key or item overloading these operators became more difficult.
I isolated the problem to make it easier to work on, additionally, I have tried playing around with both a node and a node pointer to see if I can get one to work without the other.
Here is the class I have made to test the problem, this class is not templated and works fine.
test.h
class myClass
{
public:
using Key = int;
myClass(Key);
friend std::ostream & operator<<(std::ostream &, const myClass &);
private:
struct Thing {
Key data;
Thing();
Thing(Key);
};
Thing* B;
Thing A;
void disp(std::ostream &) const;
friend std::ostream & operator<<(std::ostream &, myClass::Thing);
friend std::ostream & operator<<(std::ostream &, myClass::Thing *);
};
test.cpp
myClass::Thing::Thing(Key Num) { data = Num; }
myClass::myClass(Key Num)
{
A = Thing(Num); B = &A;
}
void myClass::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
std::ostream & operator<<(std::ostream & os, const myClass & c)
{
c.disp(os); return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing th)
{
os << th.data; return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing *th)
{
os << th->data; return os;
}
With this class, I can easily make an instance of my class and std::cout it giving the output as expected.
Then turning this class into a template:
template <class T> class myTemplate
{
public:
using Key = T;
myTemplate(Key);
template<class A>
friend std::ostream & operator<<(std::ostream &, const myTemplate<A> &);
private:
struct Thing;
Thing A;
Thing* B;
void disp(std::ostream &) const;
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing);
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing *);
};
template <class T> struct myTemplate<T>::Thing
{
T data;
Thing() = default;
Thing(Key);
};
//Create new thing A with B a pointer to A
template <class T> myTemplate<T>::myTemplate(Key Num)
{
A = Thing(Num);
B = &A;
}
//Displays Node A & B
template <class T> void myTemplate<T>::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
template <class T> myTemplate<T>::Thing::Thing(Key Num)
{
data = Num;
}
//Overloading << will call disp function, in turn print A & B to stream
template<class T> std::ostream & operator<<(std::ostream & os, const myTemplate<T> & c)
{
c.disp(os); return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing th)
{
os << th.data; return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing *th)
{
os << th->data; return os;
}
However with myTemplate when I tried in the main():
myTemplate Template(5);
cout << Template;
The code will not compile as I get the error:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const myTemplate<std::string>::Thing' (or there is no acceptable conversion)
Additionally commenting out the line:
os << A << std::endl;
So only B is being outputted to the stream, the code will compile. However the data of B is not outputted, only the memory address of B.
I have noticed that using breakpoints when trying to output B the code does not even use the overload function I defined. This is not the case for the non-templated class as the overloads I defined are used for both A and B.
So what is the correct way to overload the ostream operator to work for the struct member?
Apologises for the long winded question, felt I should include what I had determined myself.
Since template implementation is going to be in a single translate unit(header file) itself, you are not going to gain anything more, by tearing the things apart. Therefore, keep the definitions and non-member functions inside the class itself, which will provide you with much clear code and also improve the readability of the template class:
See this
#include <iostream>
template <class T> class myTemplate
{
public:
using Key = T;
private:
struct Thing
{
T data;
Thing() = default;
Thing(Key Num) : data(Num) {}
};
Thing A;
Thing* B = nullptr;
public:
myTemplate(Key Num) : A(Thing(Num)), B(&A) {}
friend std::ostream & operator<<(std::ostream& out, const myTemplate &obj)
{
return out << obj.A << std::endl << obj.B << std::endl;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing thing)
{
return out << thing.data;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing *thing)
{
return out << thing->data;
}
};
int main()
{
myTemplate<int> obj(10);
std::cout << obj;
return 0;
}
Update: If the final aim of providing that two operator<< overloads to the struct Thing is just to conveniently call in the operator<< of the myTemplate class, then you do not need that, rather simply print the data directly in operator<< of the myTemplate class. That will again reduce significate amount of codes(if that is the case!).
Nevertheless, now you can provide a specialization for the non-member(friend) function(i.e, operator<<) for the myTemplate class, as follows:
template <class T> class myTemplate; // forward declaration
template <class T> std::ostream& operator<<(std::ostream& out, const myTemplate<T> &obj);
template <class T> class myTemplate
{
private:
using Key = T;
private:
template <class Type = T> struct Thing
{
Type data;
Thing() = default;
Thing(const Key Num) : data(Num) {}
};
private:
Thing<> A;
Thing<> *B = nullptr;
public:
myTemplate(const Key Num) : A(Thing<>(Num)), B(&A) {}
friend std::ostream & operator<<<>(std::ostream& out, const myTemplate &obj);
};
template <class T> std::ostream & operator<<(std::ostream& out, const myTemplate<T> &obj)
{
return out << obj.A.data << std::endl << obj.B->data << std::endl;
}

How do I overload % operator for a template class?

I created a template class Number. I overloaded << operator but I'm not able to get % operator working.
template<typename t>
class Number
{
private:
t n;
public:
Number(t a) :n{ a } {};
Number() :n{ t() } {};
friend ostream & operator<<<>(ostream & os, const Number<t>& a);
friend Number<t> operator%(Number<t> a, Number<t> b);
};
template<typename t>
ostream & operator<<<>(ostream & os, Number<t> a)
{
os << a.n;
return os;
}
template<typename t>
Number<t> operator%(Number<t> a, Number<t> b)
{
return Number<t>(a.n % b.n);
}
As you can see <> in << operator definition, that does the job for it. But if I use that in % operator definition, I get a syntax error and if I don't I get
"1 unresolved external" error. So my problem can be summed up in two questions-
1. Why do we need to use <> while overloading operator using friend notation?
2. Why its not working for % operator?
Method 1
Declare the functions before the definition of the class template.
template <typename t> class Number;
template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a);
template <typename t>
Number<t> operator%(Number<t> a, Number<t> b);
Define the class. Make sure the friend declarations use the template parameter.
template <typename t>
class Number
{
private:
t n;
public:
Number(t a) :n{ a } {};
Number() :n{ t() } {};
// This makes sure that operator<< <int> is a friend of Number<int>
// but not of Number<double>
friend std::ostream & operator<< <t>(std::ostream & os, const Number& a);
friend Number operator%<t>(Number a, Number b);
};
Implement the functions outside the class definition.
template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a)
{
os << a.n;
return os;
}
template <typename t>
Number<t> operator%(Number<t> a, Number<t> b)
{
return Number(a.n % b.n);
}
Working code at http://ideone.com/dx3fC0.
Method 2
Implement the friend functions inside the class template definition.
template <typename t>
class Number
{
private:
t n;
public:
Number(t a) :n{ a } {};
Number() :n{ t() } {};
friend std::ostream& operator<<(std::ostream & os, const Number& a)
{
os << a.n;
return os;
}
friend Number operator%(Number a, Number b)
{
return Number<t>(a.n % b.n);
}
};
Working code at http://ideone.com/5PYQnR.
If the friend functions are not overly complex, it is better to use the second method. The overall code structure is simple. If the friend functions are complex, it might make sense to use the first method and implement them outside the class definition.
You should first declare the operator as a function template before "befriending" it in the class. See this and this for more details on how to properly do that.
The reason you got away with operator << I suspect, is a using namespace std not shown in your question, which brings in the templated operator << declaration from <iostream>.
This should work:
#include <iostream>
template<typename T>
class Number;
// Declare the operators here.
template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a);
template<typename T>
Number<T> operator%(Number<T> a, Number<T> b);
template<typename T>
class Number
{
private:
T n;
public:
Number(T a) :n{ a } {};
Number() :n{ T() } {};
friend std::ostream & operator<< <T>(std::ostream & os, const Number& a);
friend Number operator% <T>(Number a, Number b);
};
template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a /* was Number<T> ==> signature mismatch */)
{
os << a.n;
return os;
}
template<typename T>
Number<T> operator%(Number<T> a, Number<T> b)
{
return Number<T>(a.n % b.n);
}
int main() {
Number<int> a(5);
Number<int> b(6);
auto c = a % b;
std::cout << a << std::endl;
return 0;
}
Define these functions in the class body and save yourself the hassle. Also, in case that the left-hand side operand of % is Number you don't have to make it a friend.
#include <iostream>
using std::ostream;
template<typename t>
class Number
{
private:
t n;
public:
Number(t a) :n{ a } {};
Number() :n{ t() } {};
Number operator%(Number rhs)
{
return Number(n % rhs.n);
}
friend ostream & operator<<(ostream & os, Number a)
{
os << a.n;
return os;
}
};
int main()
{
Number<int> n1(4);
Number<int> n2(2);
std::cout << n1 << ' ' << n2 << '\n';
Number<int> n3 = n1 % n2;
std::cout << n3 << '\n';
}
You could make the friend operator a templated operator itself:
template<typename t>
class Number
{
private:
t n;
public:
Number(t a) :n ( a ){};
Number() :n( t() ) {};
template<typename TT>
friend Number<TT> operator%(Number<TT> a,const Number<TT>& b);
};
template<typename t>
Number<t> operator%(Number<t> a,const Number<t> &b)
{
return Number<t>(a.n % b.n);
}
int _tmain(int argc, _TCHAR* argv[])
{
Number<int> a;
Number<int> b;
Number<int> c = a %b;
return 0;
}
See explanation about extrovert declaration here.

Use of overloaded operator ambiguous

The following code:
typedef void HELPER;
const HELPER* helper = _helper;
inline ostream& operator <<(ostream& out, const HELPER* arg)
{ out << (const char*)(arg); return out; }
Blows up if I attempt a
cout << helper;
Specifically, I get:
main.cpp:35:28: error: use of overloaded operator '<<' is ambiguous
(with operand types 'basic_ostream >' and 'const HELPER *' (aka 'const void *'))
and it lists a few candidates:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:207:0: note: candidate function
basic_ostream& operator<<(const void* __p);
^
main.cpp:25:17: note: candidate function
inline ostream& operator <<(ostream& out, const HELPER* arg)
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:195:20: note: candidate function
basic_ostream& operator<<(bool __n);
^
I'm a little surprised that my typedef isn't invoking a stronger type matching here. How can I get this operator overload running?
EDIT: Further clarification, the purpose of this code is that I am dual-targeting a set of Arduino libraries. They manage their strings frequently with:
typedef void __FlashStringHelper;
void showHelp(const __FlashStringHelper* helpText)
{
Serial.print(helpText);
}
I like iostream and planned on this dual target, so I overloaded << on Serial object and made the previous into (this is the oversimplified version, for example)
#define cout Serial
void showHelp(const __FlashStringHelper* helpText)
{
cout << helpText;
}
Now I want to actually target real iostream for a different arch, but the old Arduino code can't vary (much) from its __FlashStringHelpers. That's where I'm at
typedef doesn't create types it aliases them,
inline ostream& operator <<(ostream& out, const HELPER* arg)
is equivalent to
inline ostream& operator <<(ostream& out, const void* arg)
Maybe you wanted to create a type named HELPER
class HELPER{};
As Zekian answered your question this here is something that may be of use to you or help you to achieve what you are trying to do.
#include <iostream>
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
int main() {
Helper<int> helper( 3 );
std::cout << helper << std::endl;
return 0;
}
It is a wrapper class template with an overloaded ostream operator<<. This will work for integral and atomic types. If you pass another struct or class object then you will have to define other overloaded ostream operators for them.
Example - Same Class Template, but this time using a class or struct.
#include <iostream>
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
struct Staff {
int employees = 4; // Default to 4
};
int main() {
Staff staff;
Helper<Staff> helper( staff );
std::cout << helper << std::endl; // will not compile
return 0;
}
To fix this ostream will need an overloaded operator for Staff object
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
struct Staff {
int employees = 4;
inline friend std::ostream& operator<< ( std::ostream& out, const Staff& rhs );
};
std::ostream& operator<<( std::ostream& out, const Staff& rhs ) {
return out << rhs.employees;
}
int main() {
Staff staff;
Helper<Staff> helper( staff ); // Default to 4
std::cout << helper << std::endl; // Will Print 4
// To Change Staff's Employee count for the helper wrapper do this:
staff.employees = 12; // Change To 12
helper.setObj( staff ); // pass the changed struct back into helper
std::cout << helper3 << std::endl; // Will Now Print 12
// And For Other Default Types
Helper<int> helper2( 3 );
std::cout << helper2 << std::endl;
Helper<float> helper3( 2.4f );
std::cout << helper3 << std::endl;
return 0;
}