passing a templated class with constants as an argument - c++

My template class looks like this:
template<unsigned WIDTH, unsigned HEIGTH, typename T = int> class matrix { ... }
So plain and simple, the template arguments determine this size of the matrix. The size is logically constant, so I implemented it to be consant. But when I try to write a function that accepts my matrix, I run into the following problem:
std::ostream& operator<<(std::ostream &os, const matrix &m){ ...}
Writen like so, the compiler rightfully objects the lack of template arguments... But
std::ostream& operator<<(std::ostream &os, const matrix<unsigned, unsigned> &m){ ...}
triggers this error: error: expected a constant of type 'unsigned int', got 'unsigned> int'
Which is also kind of true, since matrix expects constants, not types.
How to deal with this? I'm sure I'm not the frst to encounter this problem, what's the most "canonical" way to approach this problem of passing constant-parametrized templates?

Declare your operator<<(ostream&) overload for your template class matrix as a template which should be the obvious solution here
template<unsigned WIDTH, unsigned HEIGTH, typename T = int>
class matrix
{
public:
T arr[WIDTH][HEIGTH];
};
template<unsigned WIDTH, unsigned HEIGTH, typename T>
std::ostream& operator<<(std::ostream &os, const matrix<WIDTH, HEIGTH,T> &m)
{
// formatting inserter of m onto os
return os;
}
int main()
{
matrix<10, 10> m;
std::cout << m << std::endl;
}
But generally speaking, if your operator<<(ostream&) needs access to your private data (which generally would), you would end up declaring it as friend. If you do not want to repeat the remplate parameters, place the operator<<(ostream&) non-member friend in the scope of your matrix class
template<unsigned WIDTH, unsigned HEIGTH, typename T = int>
class matrix
{
T arr[WIDTH][HEIGTH];
friend std::ostream& operator<<(std::ostream &os, const matrix &m)
{
// formatting inserter of m onto os
return os;
}
};

Option #1
Declare the operator<< as a friend function in the scope of the matrix class:
template<unsigned WIDTH, unsigned HEIGTH, typename T = int>
class matrix
{
friend std::ostream& operator<<(std::ostream &os, const matrix& m)
// ^^^^^^ plain name
{
return os;
}
};
Option #2
Make operator<< a function template as well:
template<unsigned WIDTH, unsigned HEIGHT, typename T>
std::ostream& operator<<(std::ostream &os, const matrix<WIDTH, HEIGHT, T>& m)
// ^^^^^ ^^^^^^ ^
{
return os;
}

Overloaded operator<< needs to be template as well:
template<unsigned WIDTH, unsigned HEIGHT, typename T>
std::ostream& operator<<(std::ostream &os, const matrix<WIDTH, HEIGHT, T> &m){
// ...
return os;
}

Related

Overloading ostream of vector template with iterator

Why I can't use iterator in ostream overloading?
If I use the same declaration using iterative approach it works.
Consider the following code:
template <class T>
class List {
template <class U>
friend ostream &operator<<(ostream &os, const List<U> &rhs);
private:
vector<T> v;
};
template<class U>
ostream & operator<<(ostream & os, const List<U>& rhs)
{
vector<U>::iterator it = rhs.v.begin();
return os;
}
int main()
{
List<int> list;
cout << list << endl;
return 0;
}
Note that rhs is declared as reference to const, then rhs.v will be const too, then rhs.v.begin() will return a std::vector<U>::const_iterator, which can't be converted to std::vector<U>::iterator directly.
You should use typename for dependent type names.
So change it to
typename vector<U>::const_iterator it = rhs.v.begin();
BTW: void main() should be int main().
Try with
typename vector<U>::const_iterator it = rhs.v.begin();
If your rsh is const, you should use a const_iterator

Overloading output stream to print entire matrix

I'm trying to make << output an entire matrix which I wrote a template for. Not sure why this isn't working, the error is:
error: no match for 'operator[]' (operand types are 'matrix<int' and 'int')
candidate is:
matrix<Comparable> matrix<Comparable>::operator[](matrix<Comparable>&) [with Comparable = int]|
no known conversion for argument 1 from 'int' to 'matrix<int>&'|
which refers to this line: o << rhs[ i ][ j ]. Am I supposed to overload [ ] as well?
matrix.h:
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
size_t NumRows();
size_t NumCols();
};
matrix.cpp:
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){
size_t c = rhs.NumRows();
size_t d = rhs.NumCols();
for (int i = 0; i < c; i++){
for (int j = 0; j < d; j++){
o << rhs[i][j]; //error
}
}
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
return num_cols_;
}
And probably irrelevant but I implemented the matrix like this:
array_ = new Comparable*[num_rows_];
for (int i = 0; i < num_rows_; i++){
array_[i] = new Comparable[num_cols_];
Your function signatures don't match:
ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
is not
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs);
Notice that one is not a template, and the other is. Also, the first has a const reference argument for rhs and the second has just a reference. This mismatch means the function you define isn't Matrix's friend, and so can't access the private (or protected members of Matrix)
What you want is to declare a templated function, and then inform the compiler that a single instantiation (say ostream& operator<<(ostream& out, const matrix<int>& val) ) is the single function you want to be friends with matrix<int>.
To do this, you need to declare that you want only a specific version of the function template, and to do that you need to declare the template, and to do that you need to declare the templated class.
Ultimately that whole chain of declarations might look something like this:
#include <iostream>
// forward declare the class so the compiler knows what's up at the
// templated operator<< declaration.
template <typename T>
class Foo;
// forward declare the templated operator<< so the compiler knows you're
// 'friend'ing a specific instantiation of this template in the
// class definition.
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value);
template <typename T>
class Foo{
// declare the instantiation of the operator<< template that shares
// T with the class template to be a friend:
// operator<<<> can be separated out into operator<< <>
friend std::ostream& operator<<<>(std::ostream& out, const Foo<T>& value);
int bar_;
public:
Foo(int bar) : bar_{bar}{}
};
// now that you know the contents of `Foo<T>`, define the templated operator<<
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value){
return std::cout << "Foo: " << value.bar_;
}
int main(){
Foo<int>
a{2},
b{3};
std::cout << a << '\n' << b;
}
Live on Coliru
You can read further on Template Friends on the C++ Super-FAQ.
You can declare a get function to access array_ instead of making it as an public member;

<< operator overloading for template class object

I have written a C++ STL like bitset class:
template<size_t N>
class bitset {
public:
...........
friend std::ostream& operator << (std::ostream &, bitset<N> const&);
private:
..........
};
// end of class
template<size_t N>
std::ostream& operator << (std::ostream &os, bitset<N> const& rhs) {
............
.........
return os;
}
And I am trying to use it like this:
bitset<5> foo; // success
std::cout << foo << std::endl; // fail
And the error message is -
undefined reference to `operator<<(std::ostream&, bitSet<5u> const&)
What's the problem actually?
Your friend's declaration must be a template as well, just like the definition is:
template <size_t N>
class bitset {
public:
template <size_t M>
friend std::ostream& operator << (std::ostream &, bitset<M> const&);
};
template <size_t M>
std::ostream& operator << (std::ostream &os, bitset<M> const& rhs) {
return os;
}
Alternatively, you could declare the operator<< directly within the class scope:
template<size_t N>
class bitset {
public:
friend std::ostream& operator << (std::ostream & os, bitset const&) {
return os;
}
};
Some possible answers to your question are given here.
In addition to the answer of Piotr S., you can also predeclare the function templates:
template<size_t N> class bitset;
template<size_t N> std::ostream& operator << (std::ostream &, bitset<N> const&);
//now comes your class definition

Friend operator in template struct raises redefinition error

Consider this code:
template<typename T,typename K>
struct A{
friend std::ostream& operator<<(std::ostream& out, K x) {
// Do some output
return out;
}
};
int main(){
A<int,int> i;
A<double,int> j;
}
It does not compile, because the two instantiations of A instantiate the operator<< two times with the same signature, so I receive this error:
test.cpp:26:25: error: redefinition of ‘std::ostream& operator<<(std::ostream&, int)’
friend std::ostream& operator<<(std::ostream& out, K x) { return out; }
^
test.cpp:26:25: error: ‘std::ostream& operator<<(std::ostream&, int)’ previously defined here
How to fix this? How can I have a friend operator in a template, when that operator might have the same signature for two different instantiations? How can I solve this without triggering a redefinition error?
I don't really see any use in declaring a friend like this, nevertheless this is how you can do it:
template<typename T, typename K>
struct A{
template<typename L>
friend std::ostream& operator<<(std::ostream& out, L const &x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) {
// ...
return out;
}
LIVE DEMO
Edit:
Another option probably closer to what you want will be:
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x);
template<typename T, typename K>
struct A{
friend std::ostream& operator<<<K>(std::ostream& out, K const &x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) {
// ...
return out;
}
LIVE DEMO
But really not sure why you want this. IMHO your design has serious flaws.
Your question is faulty in the following way.
Assuming it's a stub and your class has something private such that it needs to declare a friend, the purpose of doing so is that the friend is external to the class itself but has access to what is private within it.
In your case you are declaring streaming functions of a parameter as a friend. That is fine. It means if someone creates a class Bar and wants to define how a Bar is streamed their implementation may access anything in A<T,Bar> for any type T.
The clashing of your template with operator<<( ostream&, int) is not actually a problem as the compiler knows which one to pick. It will always pick the exact match non-templated over the templated one. Your problem is that you have 2 templated ones and the compiler cannot pick between them because they are both equally valid.
Maybe something like this is what you are really trying to achieve
template< typename X, typename Y >
struct A
{
friend void a_print( std::ostream& Y const & ); // foo external function with Y as parameter, can access this
};
std::ostream & operator<<( std::ostream & out, Bar const& bar )
{
a_print( out, bar );
return out;
}
void a_print( Bar const& bar, std::ostream & out )
{
// implement and call private members of A<Foo, Bar>
return out;
}
You could make the streaming template a friend and implement the one for Bar to stream using a specific implementation.
Factor the method out to a base class:
template <typename K>
struct ABase
{
friend std::ostream& operator<<(std::ostream& out, K x) {
// Do some output
return out;
}
};
template <typename T,typename K>
struct A : public ABase<K>
{};
If you want to stream an A object, the proper signature should have been
template<typename T,typename K>
struct A{
friend std::ostream& operator<<(std::ostream& out, const A& x) {
// Do some output
return out;
}
};
taking an A<T,K> for which you can access private members, not a K.
If there is no way to get an A from K (and cannot be if K is int), making <<(ostream&,K) a friend of A gives no benefits.

C++ templates and friend declaration

Can someone tell me whats wrong with my code. I'm guessing that I didn't overload << correctly, but I'm not sure how to fix it.
The below code implements a simple Stack container. It fails at cout << si;
update: Made suggested changes, still not compiling.
update2: Got it! Thanks!
#include <iostream>
using namespace std;
template <typename T = int, int N = 10>
struct Stack
{
T elems[N];
unsigned int size;
Stack()
{
size=0;
}
void push(T e)
{
elems[size]=e;
size++;
}
T pop()
{
size--;
return elems[size];
}
template <typename T, int N>
friend ostream& operator << (ostream& os, const Stack<T, N> &stack);
};
template <typename T, int N>
ostream& operator << (ostream& os, const Stack<T, N> &stack)
{
for (unsigned int i=0; i<N; i++)
{
os << stack.elems[i];
}
return os;
}
int main()
{
Stack<> si;
si.push(3);
cout << si;
}
template <typename T, int N>
ostream& operator << (ostream& os, const Stack<T> &stack)
The problem with this template is that the parameter N cannot be inferred from either of the function arguments because you are using the default template argument for the Stack argument.
Looking at your implementation, you almost certainly didn't intend this as you use N as the loop bound whereas Stack<T> has 10 elements. You probably meant to write:
template <typename T, int N>
ostream& operator << (ostream& os, const Stack<T, N> &stack)
Also, your friend declaration needs to match the template, at the moment the friend declaration is declaring a non-template friend overload.
This would declare an appropriate friend template.
template< typename S, int M >
friend ostream& operator << (ostream& os, const Stack<S, M> &stack);
Should be
ostream& operator << (ostream& os, const Stack<T,N> &stack);
// ^^ -- note this
in both definition and declaration.
You need to fully specify all template arguments for your stack here:
template <typename T, int N>
ostream& operator<< (ostream& os, const Stack<T, N> &stack);
other wise the compiler can't deduce the proper N for your overloaded streaming operator.
You already got your answers, but may I suggest turning:
void push(T e)
into:
void push(const T& e)
for performance wise, since you have no idea what T will be, and passing it on the stack isnt a good idea.