Overriding << operator for templated struct - c++

numcpp.h file
#include "iostream"
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
friend std::ostream& operator << (std::ostream& out, const mf& mat);
};
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
I am trying to overload << operator for cout to be able to print mf. First I tried making the overloading function a friend that directly takes mf as argument. I did this because if I took Matrix as argument, I would need to deal with template and I don't know how to do that.
numcpp.cpp file
#include "numcpp.h"
namespace numcpp{
std::ostream& operator << (std::ostream& out, const mf& mat)
{
//overloaded out here
return out;
}
}
main.cpp
#include "iostream"
#include "numcpp.h"
int main()
{
numcpp::mf inputs;
// inputs is filled with random numbers here
std::cout << inputs;
}
But this gives an error identified mf is undefined in .h file in line friend std::ostream& operator << (std::ostream& out, const mf& mat);
So I ditched this approach and tried removing the friend function declaration from Matrix without changing the .cpp file. But now I get a different error saying no operator << matches these operands.
I think this is because the overload is done in numcpp namespace so it is not visible from main which is outside the namesapce.

What you normally want is to define a template in your header file. The definition needs to be available at the call-site to allow the compiler to make an instatiation of the template.
If possible, the easiest way is to put the definition in the class definition.
template<typename T>
struct Matrix
{
std::vector<T> m;
// using Matrix here is allowed and refers to the current instatiation, equivalent to writing Matrix<T>
friend std::ostream& operator << (std::ostream& out, const Matrix& mat) {
...
return out;
}
};

Try change your numcpp.h to
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
typedef Vector<float> vf;
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
inline friend std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat);
};
inline std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat)
{
//overloaded out here
return out;
}
typedef Matrix<vf> mf;
}
You are getting this error because mf was not declared when you trying to use it.
Also, you can add the body of the function directly in the definition to get rid of the inline.

The typedefs are not available inside the definition of your class Matrix. You can either declare the typedef before the class definition (#Alloces' answer) of just template the overloaded operator:
#include <vector>
#include <sstream>
#include <iostream>
namespace numcpp {
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
template<typename K> // template parameter must not be named T
inline friend std::ostream& operator << (std::ostream& out, const Matrix<K>& mat);
};
template<typename K>
inline std::ostream& operator << (std::ostream& out, const Matrix<K>& mat)
{
return out << "Just a test";
}
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
int main() {
numcpp::mf inputs;
std::cout << inputs << "\n"; // Just a test
}

Related

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;
}

Check if an integer function [duplicate]

When I'm writing a function in a template class how can I find out what my T is?
e.g.
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}
How can I write the above if statement so it works?
Something like this:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value)
// ...
}
Since C++11 we have std::is_same:
if (std::is_same<T, int>::value) ...
It's implemented similar to the suggested trait TypeIsInt suggested in the other answers,
but with two types to be compared.
Define it explicitly, e.g.:
template <>
ostream& operator << (ostream &out,Vector<int>& vec)
{
}
Simplest, most general solution:
Just write a plain old overload of the function:
ostream& operator << (ostream &out,Vector<int>& vec)
{
// Your int-specific implementation goes here
}
This assumes that the int and non-int versions don't have much code in common, as you have to write two separate implementations.
IF you want to use one common implementation of the function, with just an if statement inside that differs, use Charles Bailey's implementation:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value) {
// your int-specific code here
}
}
In general, don't use typeid if you don't need to.
The easiest way is to provide a template specialisation:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> struct A {
};
template <typename T >
ostream & operator <<( ostream & os, A<T> & a ) {
return os << "not an int" << endl;
}
template <>
ostream & operator <<( ostream & os, A<int> & a ) {
return os << "an int" << endl;
}
int main() {
A <double> ad;
cout << ad;
A <int> ai;
cout << ai;
}
This way.
ostream & operator << (ostream &out, Vector<int> const & vec)
{
// ...
}
The compiler will choose this function over the function template if you pass Vector<int>.
Edit: I found this article, which attempts to explain why to prefer overloading to template specialization.
TypeID is never a good idea. It relies on RTTI.
By the way here is your answer :http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7
One more solution is:
if(std::is_same<T, int>::value)
//It is int
if (std::is_same<T, double>::value)
//It is double
if (std::is_same<T, long double>::value)
//It is long double
C++ templates don't work this way. The general idea of templates is express somethings which is common for a lot of different types. And in your case you should use template specialization.
template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
{
// your general code for all type
}
// specialized template
template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
{
// your specific to iny type code goes here
}
Then C++ compiler will call this function when you use int type and general implementation for any other type
std::vector<int> f(5, 5);
std::cout << f;

ostream friend function of specialized template class

template <>
class test<int> {
int y;
public:
test(int k) : y(k) {}
friend ofstream& operator<< <test<int>> (ofstream& os, const test<int>& t);
};
template<>
ofstream& operator<< <test<int> > (ofstream& os, const test<int>& t)
{
os << t.y;
return os;
}
The code above is specialized template class of test in a int version. I am trying to overload ofstream operator<< function. But it shows error message;
C2027: use of undefined type 'std::basic_ofstream<_Elem,_Traits>'
Besides, the same method works on a ordinary function (not ofstream operator<< but the function that I make) Is there anyway to us operator<< function of ofstream in a specialized template class ?
You need to include
#include <iostream>
At the time of instantiation of the function template. Perhaps you only included
#include <iosfwd>
Besides, you shouldn't be defining (static) friend as a template: https://ideone.com/1HRlZ
#include <iostream>
template <typename> class test;
template <>
class test<int> {
int y;
public:
test(int k) : y(k) {}
friend std::ostream& operator<<(std::ostream& os, const test& t);
};
std::ostream& operator<< (std::ostream& os, const test<int>& t)
{
return os << t.y;
}
int main()
{
test<int> a(42);
std::cout << a << std::endl;
}
Note that it isn't a good idea to have 'using namespace std' in your header file, which is why I removed it from the sample. (It might cause conflicts for users of your header file when they include your header)
There are a number of interesting issues here. First the obvious housekeeping
You should #include <fstream> and don't forget using namespace std.
operator << shouldn't be a template, it should be an overloaded function.
os << t.y confuses the compiler for me (g++ 4.4.3: "warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:"). You intend to push the int to the stream obviously, but the compiler notices that an int can be turned into a test<int> via your constructor and therefore it doesn't know whether you want to push an int or a test<int>. This is stupid I know, and can be solved by making the constructor explicit.
#include <fstream>
using namespace std;
template <typename T>
class test;
template <>
class test<int> {
int y;
public:
explicit test(int k) : y(k) {}
// friend ofstream& operator<< < test<int> > (ofstream& os, const test<int>& t);
friend ofstream& operator<< (ofstream& os, const test<int>& t);
};
// template<>
// ofstream& operator<< <test<int> > (ofstream& os, const test<int>& t)
ofstream& operator<< (ofstream& os, const test<int>& t)
{
os << t.y;
return os;
}
int main() {
}

operator<<(ostream&, X) for class X nested in a class template

This one compiles and works like it should (non-nested template):
#include <iostream>
template<typename T> class Z;
template <typename T>
std::ostream& operator<< (std::ostream& os, const Z<T>&) {
return (os << "Z");
}
template<typename T> class Z {
friend std::ostream& operator<< <> (std::ostream& os, const Z&);
};
int main () {
Z<int> z;
std::cout << z << std::endl;
}
This one doesn't compile (gcc 4.4 and gcc 4.6, in both 03 and 0x mode):
#include <iostream>
template<typename T> class Z;
template<typename T>
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
return (os << "ZZ!");
}
template <typename T> class Z {
public:
class ZZ {
friend std::ostream& operator<< <> (std::ostream& os, const ZZ&);
};
};
int main () {
Z<int>::ZZ zz;
std::cout << zz << std::endl;
}
The error message looks like this:
error: template-id ‘operator<< <>’ for ‘std::ostream& operator<<(std::ostream&,
const Z<int>::ZZ&)’ does not match any template declaration
error: no match for ‘operator<<’ in ‘std::cout << zz’
In the 0x mode the second error message is different, but the meaning is the same.
Is it possible to do what I want to do?
EDIT Apparently, there's an instance of non-deduced context here, which explains the error messages. The question, however, still stands: can I have a working operator<< for a class nested in a class template?
This is a general problem for functions:
template <typename C>
void func(typename C::iterator i);
Now, if I call func(int*), which value of C should I use ?
In general, you cannot work backward ! Many different C could have defined an internal type iterator that happens to be a int* for some set of parameters.
In your case, you are complicating the situation a bit:
template <typename T>
void func(typename Z<T>::ZZ const&);
But fundamentally this is the same issue, Z<T> is a template, not a full class, and you are asking to create a function for the inner type ZZ of this template.
Suppose I do:
template <typename T>
struct Z { typedef T ZZ; };
template <typename T>
struct Z<T const> { typedef T ZZ; };
Note: typical of iterators, the value_type is not const-qualified
Then, when invoking func(int), should I use Z<int> or Z<int const> ?
It is non-deducible.
And thus the whole thing is referred to as a non-deducible context, and the Standard forbids it because there is no sensible answer.
Rule of Thumb: be suspicious of typename in the parameters of a function.
Note: they are OK if another argument already pinned down the type, example typename C::iterator find(C&, typename C::const_reference); because once C is deduced, then C::const_reference may be used without trouble
Apart from the problem that the friend declaration doesn't match the operator template (perhaps fixable as)
class ZZ {
template<class U>
friend std::ostream& operator<<(std::ostream& os, const ZZ&);
};
you also have a problem with a "non-deduced context", which is what Matthieu links to.
In this template
template<typename T>
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
return (os << "ZZ!");
}
the compiler isn't able to figure out for what T's you parameter will match. There could be several matches, if you specialize for some types
template<>
class Z<long>
{
public:
typedef double ZZ;
};
template<>
class Z<bool>
{
public:
typedef double ZZ;
};
Now if I try to print a double, T could be either bool or long.
The compiler cannot know this for sure without checking for all possible T's, and it doesn't have to do that. It just skips your operator instead.
Matthieu explained the problem very well, but a simple work-around can be used in this case.
You can implement the friend function inside the class with the friend declaration:
#include <iostream>
template <typename T> class Z {
public:
class ZZ {
friend std::ostream& operator<< (std::ostream& os, const ZZ&) {
return os << "ZZ!";
}
};
};
int main () {
Z<int>::ZZ zz;
std::cout << zz << std::endl;
}
A different technique is to provide an out of line class template which works like a hook.
template <typename T> class ZZZ {
T &getDerived() { return static_cast<T&>(*this); }
T const &getDerived() const { return static_cast<T const&>(*this); }
protected:
~ZZZ() { }
};
template <typename T> class Z {
public:
class ZZ : public ZZZ<ZZ> {
};
};
template<typename ZZ>
std::ostream& operator<< (std::ostream& os, const ZZZ<ZZ> &zzz) {
ZZ const& zz = zzz.getDerived();
/* now you can use zz */
return (os << "ZZ!");
}
Using a friend function definition is preferable though. But it's good to know about alternatives.

how to query if(T==int) with template class

When I'm writing a function in a template class how can I find out what my T is?
e.g.
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}
How can I write the above if statement so it works?
Something like this:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value)
// ...
}
Since C++11 we have std::is_same:
if (std::is_same<T, int>::value) ...
It's implemented similar to the suggested trait TypeIsInt suggested in the other answers,
but with two types to be compared.
Define it explicitly, e.g.:
template <>
ostream& operator << (ostream &out,Vector<int>& vec)
{
}
Simplest, most general solution:
Just write a plain old overload of the function:
ostream& operator << (ostream &out,Vector<int>& vec)
{
// Your int-specific implementation goes here
}
This assumes that the int and non-int versions don't have much code in common, as you have to write two separate implementations.
IF you want to use one common implementation of the function, with just an if statement inside that differs, use Charles Bailey's implementation:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value) {
// your int-specific code here
}
}
In general, don't use typeid if you don't need to.
The easiest way is to provide a template specialisation:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> struct A {
};
template <typename T >
ostream & operator <<( ostream & os, A<T> & a ) {
return os << "not an int" << endl;
}
template <>
ostream & operator <<( ostream & os, A<int> & a ) {
return os << "an int" << endl;
}
int main() {
A <double> ad;
cout << ad;
A <int> ai;
cout << ai;
}
This way.
ostream & operator << (ostream &out, Vector<int> const & vec)
{
// ...
}
The compiler will choose this function over the function template if you pass Vector<int>.
Edit: I found this article, which attempts to explain why to prefer overloading to template specialization.
TypeID is never a good idea. It relies on RTTI.
By the way here is your answer :http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7
One more solution is:
if(std::is_same<T, int>::value)
//It is int
if (std::is_same<T, double>::value)
//It is double
if (std::is_same<T, long double>::value)
//It is long double
C++ templates don't work this way. The general idea of templates is express somethings which is common for a lot of different types. And in your case you should use template specialization.
template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
{
// your general code for all type
}
// specialized template
template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
{
// your specific to iny type code goes here
}
Then C++ compiler will call this function when you use int type and general implementation for any other type
std::vector<int> f(5, 5);
std::cout << f;