So I'm trying to include two friend declarations for the input and output operator in a template class but every time I compile the code it doesn't seem to recognize the operator.
here is my header file.
ERROR:Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits > &,class Screen<5,5> &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#AAV?$Screen#$04$04###Z) referenced in function _main
It seems to be a linking error.
Screen.h
#include<string>
#include<iostream>
template<std::string::size_type, std::string::size_type>
class Screen;
template<std::string::size_type w, std::string::size_type h>
std::ostream& operator<<(std::ostream&,Screen<w, h>&);
template<std::string::size_type w,std::string::size_type h>
class Screen{
friend std::ostream& operator<<(std::ostream&, Screen&);
public:
Screen()=default;
Screen(const char str=' '):content(w*h,str){}
Screen& set(char);
Screen& set(std::string::size_type,std::string::size_type,char);
char get() const {return content[cursor];}
inline char get(std::string::size_type,std::string::size_type)const;
Screen& move(std::string::size_type,std::string::size_type);
Screen& display(std::ostream& os) { os<<content; return *this; }
private:
//void do_display(std::ostream& os) const { os << content; }
std::string::size_type cursor=0;
std::string content;
};
//MEMBER FUNCTIONS
template<std::string::size_type w,std::string::size_type h>
inline Screen<w,h>& Screen<w,h>::set(char c){
content[cursor] =c;
return *this;
}
template<std::string::size_type w,std::string::size_type h>
inline Screen<w,h>& Screen<w,h>::set(std::string::size_type r,std::string::size_type col,char ch){
content[r*w+col]=ch;
return *this;
}
template<std::string::size_type w,std::string::size_type h>
inline Screen<w,h>& Screen<w,h>::move(std::string::size_type r,std::string::size_type c){
cursor = r + w + c;
return *this;
}
template<std::string::size_type w,std::string::size_type h>
inline char Screen<w,h>::get(std::string::size_type r,std::string::size_type c)const{
return content[r*w+c];
}
//OS OPERATOR
template<std::string::size_type w, std::string::size_type h>
std::ostream& operator<<(std::ostream& os, Screen<w, h>& item) {
os << item.content;
return os;
}
here is my main cpp file
main.cpp
#include"Screen.h"
#include<string>
#include<iostream>
using std::cout; using std::endl;
using std::string;
int main(){
Screen<5,5> myScreen('X');
myScreen.move(4, 0).set('#').display(cout);
cout << endl;
myScreen.display(cout);
cout << endl;
cout << myScreen << endl;
}
I noticed that the problem could be fixed by including the friend declaration and the function definition inside the class body but I don't want to dot it this way.
public:
... other code
template<std::string::size_type w, std::string::size_type h>
friend std::ostream& operator<<(std::ostream& os, Screen<w, h>& item) {
os << item.content;
return os;
}
This confused me and I'm trying to understand why it works this way but not the other way, and I also noticed that when I include the friend declaration like this
friend std::ostream& operator<<<w,h>(std::ostream&, Screen&);
it seems to work but it gives me a warning letting know me know that the function definition for the operator is not found, and that confused me even more.This problem is from c++ primer 5th edition chapter 16 problem 15
friend std::ostream& operator<< <> (std::ostream&, Screen&);
--
Without these two characters, the friend declaration declares a non-template. That is, when you instantiate Screen<3,5>, it will attempt to find a function with this signature
std::ostream& operator<< (std::ostream&, Screen<3,5>&);
and not any function template. There is no such function so this will fail. The declaration that works declares a template specialisation as a friend, and the template exists and can be instantiated, so no problem here.
friend std::ostream& operator<< <w, h> (std::ostream&, Screen&);
also works exactly the same way. demo
These friend declarations require that the main template declaration
template<std::string::size_type w, std::string::size_type h>
std::ostream& operator<<(std::ostream&,Screen<w, h>&);
is in scope (which is the case with your code).
The friend inside the class should be a full specialization:
friend std::ostream& operator<< <>(std::ostream&, Screen&);
Note the <> after the function name.
See template friends.
Related
Im trying to build a vector of type template but keep getting an error
template<class T>
struct s{
T val;
public:
s(T a)
{
val = a;
};
friend ostream& operator<<(ostream& os, const T& a);
};
template <typename T>
ostream& operator<< (ostream& os, const T& a){
return os << a.val;
}
int main()
{
s <double> names(4) ;
s <int> figure(7);
s <string> word();
s <vector<int>*> arrays();
cout << names << endl;
cout << figure << endl;
cout << arrays << endl;
return 0;
}
I keep receiving the same error -
request for member 'val' in 'a', which is of non-class type 's<std::vector<int>*>()'|
Any advice will be greatly appreciated
s <vector<int>*> arrays();
Declares a function named arrays taking no arguments and returning a s<vector<int>*>. Remove the redundant parentheses or replace them with {} for C++11. Of course, your s doesn't support default construction, so you need to give it a default constructor - which can be as simple as giving the constructor a default argument:
s(T a = T())
{
val = a;
}
and it's better to use the member initialization list instead of assignment and take a const ref instead of by value, since T can be large:
s(const T& a = T()) : val(a) { }
In C++11, you should take by value and move a into val instead:
s(T a = T()) : val(std::move(a)) { }
Also,
template <typename T>
ostream& operator<< (ostream& os, const T& a){
return os << a.val;
}
would match everything under the sun. Better to match s only:
template <typename T>
ostream& operator<< (ostream& os, const s<T>& a){
return os << a.val;
}
Finally,
friend ostream& operator<<(ostream& os, const T& a);
befriends (and declares) a simple function rather than a function template. To befriend the template operator << as modified above:
template <typename U>
friend ostream& operator<<(ostream& os, const s<U>& a);
Or even better, remove the template operator and define the friend function inline (inside the class definition) instead:
friend ostream& operator<<(ostream& os, const s<T>& a){
return os << a.val;
}
This is more compact, and also limits friendship to the matching version of operator <<, rather than all instantiations of the template.
Demo.
s <vector<int>*> arrays();
This does not instantiate an object, it declares a function that returns s<vector<int>*>, and as a consequence:
cout << arrays << endl;
Tries to print out a function pointer by instantiating your templated operator<<:
template <typename T>
ostream& operator<< (ostream& os, const T& a){
return os << a.val;
}
with:
T = s<vector<int>*>(*)();
and so, a pointer to function a does not have the .val field which triggers the error.
The whole problem is that this
ClassName InstanceName();
is not creating an instance of ClassName using default constructor, but declares a function. In order to do what you wanted (and I presume that is to create instances with default constructors) use syntax
ClassName InstanceName;
So, in order to fix your errors, change
s <string> word();
s <vector<int>*> arrays();
to
s <string> word;
s <vector<int>*> arrays;
and add a default constructor to your class s.
Ambiguous overload for operator<<() is called when I add the overload function below
template <typename Container> ostream& operator<<(ostream& os, const Container& c)
{
copy(c.begin(), c.end(), ostream_iterator<typename Container::value_type>(os, " "));
return os;
}
the error is called on this function where it uses the <<.
void print_list(const list<int>& list_int)
{
for (list<int>::const_iterator it = list_int.begin(); it != list_int.end(); it++) cout << *it << " ";
}
(For reference, if anyone else is looking: http://ideone.com/YlX7q )
Your definition of operator<< can be instantiated as ::operator<<<int>(std::ostream&, const int&); this is ambigious with std::operator<<(std::ostream&, int). Calling the name of the type Container doesn't mean it is a container; overload resolution is done before the definition is instantiated.
Yes of course this cannot work.
You are introducing a templated overload, and the compiler don't know anymore what to use when you use that operator.
Simply you cannot do that.
You can do something like this:
template<class T>
friend ostream& operator<<(ostream& os, const MyClass<T>& r);
but you cannot do
template<class T>
friend ostream& operator<<(ostream& os, const T& r);
I am trying to overload the << operator, but I get the following error:
error: ambiguous overload for 'operator<<' in 'std::cout << "Test "'
..Followed by 5 billion other errors similar to:
c:\mingw\bin../lib/gcc/mingw32/4.5.2/include/c++/ostream:165:7: note:
candidates are: ...
This comes up because I'm using cout in my main.cpp file.
Here is my code:
In BinTree.h:
template <typename T>
class BinTree{
...
friend std::ostream& operator<< <>(std::ostream&, const T&);
In BinTree.cpp:
template <typename T>
std::ostream& operator<< (std:: ostream& o, const T& value){
return o << value;
}
Thanks in advance for any help you can give.
Your function has the same signature than the one already defined. This is why the compiler moans about ambigous overload. Your function tries to define a function to stream everything to a ostream. This function already exists in the standards library.
template <typename T>
std::ostream& operator<< (std:: ostream& o, const T& value){
return o << value;
}
What you perhaps want to do is write a function that defines how a BinTree is streamed (to everything). Please note that the stream type is templated. So if you chain the calls to the stream operator it streams the concrete type.
template <typename T, typename U>
T& operator<< (T& o, const BinTree<U>& value){
//Stream all the nodes in your tree....
return o;
}
Did you mean..
template<class T>
ostream& operator<<(ostream& os, const BinTree<T>& v){
typename BinTree<T>::iterator it;
for(it = v.begin(); it != v.end(); ++it){
os << *it << endl;
}
return os;
}
Post more code, till then see this part:
template <typename T>
std::ostream& operator<< (std:: ostream& o, const T& value){
return o << value;
}
This is doing nothing but calling itself. It is recursive call. The operator<< is defined to output value of type T, and when you write o<<value, it calls itself, as the type of value is T.
Second, since this is function-template, the definition should be provided in the .h file, not in .cpp file if you expect your code working by including .h file.
I have a class:
class foo {
private:
std::string data;
public:
foo &append(const char* str, size_t n) { data.append(str,n); }
// for debug output
template <typename T>
friend T& operator<< (T &out, foo const &f);
// some other stuff
};
template <typename T>
T& operator<< (T &out, foo const &f) {
return out << f.data;
}
I want this to work with any class that provides the << operator.
This works fine with std::cout as in:
std::cout << fooObject;
But the following fails:
BOOST_AUTO_TEST_CASE( foo_append_and_output_operator )
{
// fooObject is accessable here
const char* str = "hello";
fooObject.append(str, strlen(str));
output_test_stream output;
output << fooObject;
BOOST_CHECK( output.is_equal(str) );
}
g++ tells me that:
In function ‘T& operator<<(T&, const foo&)
[with T = boost::test_tools::output_test_stream]’:
error: invalid initialization of reference of type
‘boost::test_tools::output_test_stream&’ from expression of type
‘std::basic_ostream<char, std::char_traits<char> >’
What's going on?
I'm using Boost 1.34.1 on Ubuntu 8.04.
So I think I have an explanation, but no solution yet. output_test_stream implements its stream functionality by subclassing wrap_stringstream. The insertion-operator for this is a free function-template that looks like this:
template <typename CharT, typename T>
inline basic_wrap_stringstream<CharT>&
operator<<( basic_wrap_stringstream<CharT>& targ, T const& t )
{
targ.stream() << t;
return targ;
}
// ... further down in the same header
typedef basic_wrap_stringstream<char> wrap_stringstream;
Your operator is called with output_test_stream as the stream-type, and that makes this it's return-type. Your operator then calls the above operator, and just propagates the return value. The return value of the above operator however is a superclass of the returntype of your operator. When compiler tries to create the reference you want to return, it chokes, because it cannot initialize a reference to a subclass from a reference to a superclass, even if both refer to the same object. That make any sense?
You may know that already, but using output_test_stream as an std::ostream works:
class foo {
// [...]
friend
std::ostream& operator<< ( std::ostream &os, const foo &f );
};
std::ostream& operator<< ( std::ostream &os, const foo &f ) {
return os << f.data;
}
Is it a typo? You wrote
foo.append(str, strlen(str));
but foo is the name of the class and not an object.
how can i overload "<<" operator (for cout) so i could do "cout" to a class k
The canonical implementation of the output operator for any type T is this:
std::ostream& operator<<(std::ostream& os, const T& obj)
{
os << obj.get_data1() << get_data2();
return os;
}
Note that output stream operators commonly are not member functions. (That's because for binary operators to be member functions they have to be members of their left-hand argument's type. That's a stream, however, and not your own type. There is the exception of a few overloads of operator<<() for some built-ins, which are members of the output stream class.)
Therefor, if not all data of T is publicly accessible, this operator has to be a friend of T
class T {
friend std::ostream& operator<<(std::ostream&, const T&);
// ...
};
or the operator calls a public function which does the streaming:
class T {
public:
void write_to_stream(std::ostream&);
// ...
};
std::ostream& operator<<(std::ostream& os, const T& obj)
{
obj.write_to_stream(os);
return os;
}
The advantage of the latter is that the write_to_stream() member function can be virtual (and pure), allowing polymorphic classes to be streamed.
If you want to be fancy and support all kinds of streams, you'd have to templatize that:
template< typename TCh, typename TTr >
std::basic_ostream<TCh,TTr>& operator<<(std::basic_ostream<TCh,TTr>& os, const T& obj)
{
os << obj.get_data1() << get_data2();
return os;
}
(Templates, however, don't work with virtual functions.)