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.
Related
I'm trying to lift a simple Array-io manipulator I wrote to use std::vectors. Here is the old signature I had been using:
template<typename T>
struct arr {
const size_t size;
T* values;
arr(const size_t size, T* values) : size(size), values(values) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
Now I tried to lift it like so:
template<typename T>
struct arr {
std::vector<T>& vec;
arr(std::vector<T>& vec) : vec(vec) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
However I am facing the following problem: I want to use << arr(member) from inside a const declared member method. This doesnt't compile of course:
error: binding reference of type ‘std::vector<std::unique_ptr<IController> >&’ to ‘const std::vector<std::unique_ptr<IController> >’ discards qualifiers
However when I change the constructor aguments and arr::vec to const std::vector<T>& I have the opposite problem and >> arr(member) cannot work anymore!
I was hoping that by initializing the arr instance as const I could solve this but I face the same compiler error with the following line:
const streamutils::arr<int> list(myVector);
How can I solve this without declaring two different types for the in and out directions?
I attempted to look at the libstdc++ source to see how it is done for std::quoted but I couldn't figure it out.
You can parametrize your manipulator not with T but with vector<T> itself. This way you'll be able not to bother about your vector being const or not. Also create a helper function which returns the instance of your class with corresponding template type.
template<typename T>
using is_vector = std::is_same<T, std::vector<typename T::value_type, typename T::allocator_type>>;
template<typename T>
struct Arr {
static_assert(is_vector<std::decay_t<T>>::value);
T& vec;
// Note that arr is passed by value here because it is a temporary
// in expressions like 'cin >> arr(a)'
template<typename U>
friend std::enable_if_t<!std::is_const_v<U>, std::istream&> operator>>(std::istream& in, Arr<U> Arr);
template<typename U>
friend std::ostream& operator<<(std::ostream& out, const Arr<U>& Arr);
};
template<typename T>
std::enable_if_t<!std::is_const_v<T>, std::istream&> operator>>(std::istream& in, Arr<T> arr) {
int n;
in >> n;
arr.vec.resize(n);
for (int i = 0; i < n; ++i) {
in >> arr.vec[i];
}
return in;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const Arr<T>& arr) {
out << arr.vec.size() << "\n";
for (const auto& x: arr.vec) {
out << x << " ";
}
out << "\n";
return out;
}
template<typename T, typename = typename is_vector<std::decay_t<T>>::type>
Arr<T> arr(T& t)
{
return Arr<T>{t};
}
int main() {
vector<int> a;
cin >> arr(a);
cout << arr(a) << endl;
const vector<int> b{1, 2, 3};
cin >> arr(b); // compile error
cout << arr(b) << endl;
}
Also, consider reading this post, it explains various ways to make friend template operators (the one I showed here is not the best and not the only possible).
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;
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;
I thought friend functions had access to all members. Even in this question it worked:
C++ friend function can't access private members
The answer given in that question seems identical to my code, and his compiled fine while mine just says array_ is pivate. Anyone know why?
.h:
#ifndef matrix_h
#define matrix_h
#include <iostream>
using namespace std;
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();
};
#endif
.cpp:
#include <iostream>
#include "matrix.h"
using namespace std;
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.array_[i][j]; //not allowed
}
o << endl;
}
return o;
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
return num_cols_;
}
int main(){
matrix<int> a;
cout << a << endl;
}
Say you use const in both places and add const to the declarations of numRows and numCols too. Then what's the problem? Well...
You think it's identical, but your code has a template. And the friend declaration
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
is not a template, so it doesn't match the definition
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){ // ...
which is a template. In fact gcc will give a warning:
matrix.h:16:79: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, const matrix<Comparable>&)’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
^
matrix.h:16:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
It's tempting to just friend all specializations, like this:
template <typename T>
friend ostream& operator<< (ostream& o, const matrix<T> & rhs);
Unfortunately, this won't work for the reasons explained here: Why can templates only be implemented in the header file? You'll be able to compile matrix.cpp, but not a separate driver program, like this:
#include <iostream>
#include "matrix.h"
using namespace std;
int main() {
matrix<int> m;
cout << m << endl;
}
You get an undefined reference error. Instead, you really should just define your entire matrix class in the header and ditch the .cpp file.
It should be pointed out that this still has a problem: you can call this operator<< just fine, but you can't, say, take its address, because it can only be found by argument-dependent lookup.
auto ptr = static_cast<ostream&(*)(ostream&, const matrix<int>&)>(operator<<); // error
For it to be found by unqualified lookup, it must have a matching declaration at namespace scope. And it is actually impossible to write such a declaration (the syntax of C++ doesn't have any way to do it)! To fix this, we need to turn operator<< into a function template, defined inline:
template <typename Comparable>
class matrix {
// ...
template <typename T>
friend ostream& operator<<(ostream& o, const matrix<T>& rhs) {
// ...
}
// ...
};
// namespace-scope declaration
template <typename T>
ostream& operator<<(ostream& o, const matrix<T>& rhs);
Now the above code taking the address of the operator will work.
The compiler complains because the function you implement is different with the one you declare(in declaration rhs is decorated by const, in implementation it isn't).
After you add const in implementation, the compiler complains "Undefined reference" because the declaration and the implementation is still not the same. The implementation is a template function, the decalartion is not.
#ifndef matrix_h
#define matrix_h
#include <iostream>
using namespace std;
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
template<typename T>
friend ostream& operator<< (ostream& o, const matrix<T> & rhs);
size_t NumRows() const;
size_t NumCols() const;
};
template <typename Comparable>
ostream& operator<< (ostream& o, const 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.array_[i][j]; //not allowed
}
o << endl;
}
return o;
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows() const{
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols() const{
return num_cols_;
}
#endif
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;