Overloading << and >> for STL map: "cannot bind lvalue" - c++

I am trying to save an STL map containing custom objects to a file, using fstream. I am doing this using << and >> operator overloading.
#include <iostream>
#include <string>
#include <map>
#include <fstream>
#define DELIM '/'
struct Point{
public:
int x, y;
};
//operator overloads for point
std::istream& operator>>(std::istream& is, Point& p){
std::string input;
std::getline(is, input, DELIM);
p.x = std::stoi(input);
std::getline(is, input, DELIM);
p.y = std::stoi(input);
return is;
}
std::ostream& operator<<(std::ostream& os, Point& p){
os << p.x << DELIM << p.y << DELIM;
return os;
}
//operator overloads for map<string, point>
std::istream& operator>>(std::istream& is, std::map<std::string, Point>& m){
std::string input;
std::getline(is, input, DELIM);
int map_size = std::stoi(input);
for(int i = 0; i < map_size; i++){
std::getline(is, input, DELIM);
Point p; is >> p;
m[input] = p;
}
return is;
}
std::ostream& operator<<(std::ostream& os, std::map<std::string, Point>& m){
os << m.size() << DELIM;
for(const auto& pair : m){
os << pair.first << DELIM;
os << pair.second;
}
return os;
}
int main(){
Point p1;
p1.x = 1; p1.y = 2;
Point p2;
p2.x = 100; p2.y = 150;
std::map<std::string, Point> map;
map["p1"] = p1;
map["p2"] = p2;
return 0;
}
When I try to compile this file I get the following error:
test.cpp: In function 'std::ostream& operator<<(std::ostream&, std::map<std::basic_string<char>, Point>&)':
test.cpp:44:14: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
os << pair.second;
Any idea how to fix this? I ran into this problem earlier with templates, however there are no templates used here. Other answers on SO also involved templates and did not help me. An explanation of why this is happening would be appreciated too!
The command I used to compile: (MinGW, gcc 4.8.1)
g++ test.cpp -o test -std=c++11 -Wall
The full error message:
test.cpp: In function 'std::ostream& operator<<(std::ostream&, std::map<std::basic_string<char>, Point>&)':
test.cpp:44:14: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
os << pair.second;
^
In file included from c:\mingw\lib\gcc\x86_64-w64-mingw32\4.8.1\include\c++\iostream:39:0,
from test.cpp:1:
c:\mingw\lib\gcc\x86_64-w64-mingw32\4.8.1\include\c++\ostream:602:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Point]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
Thank you!!

Here
for(const auto& pair : m){
os << pair.first << DELIM;
os << pair.second;
}
pair is const, so pair.second will be const Point too, which can't match the parameter type Point& of operator<<.
Change the parameter type of Point for operator<< to const reference:
std::ostream& operator<<(std::ostream& os, const Point& p){
~~~~~
os << p.x << DELIM << p.y << DELIM;
return os;
}
Mostly, the argument passed to operator<< is not expected to be changed, so it's good practice to declare the type to const& for both operator<<.
std::ostream& operator<<(std::ostream& os, const Point& p){
std::ostream& operator<<(std::ostream& os, const std::map<std::string, Point>& m){

The argument passed to the overloaded << operator should be a constant reference, not a mutable reference.

Related

cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’

There have been a couple posts on this subject, but I think this is one of the simplest examples, and hopefully it will clarify some things about cout and initialization.
So this works:
class A {
public:
std::ostream& operator<< (std::ostream& os) {
return os;
}
};
class B {
std::ostream& operator<< (std::ostream& os) {
A a(); // <-- LOOK
std::cout << a;
return os;
}
};
But if I simply A a() to A a:
class A {
public:
std::ostream& operator<< (std::ostream& os) {
return os;
}
};
class B {
std::ostream& operator<< (std::ostream& os) {
A a; // <-- LOOK
std::cout << a;
return os;
}
};
It throws:
nvcc main.cpp util.cpp -o main -lcublas -std=c++11
In file included from main.cpp:9:0:
cout-test.hpp: In member function ‘std::ostream& B::operator<<(std::ostream&)’:
cout-test.hpp:21:20: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
std::cout << a;
^
In file included from /usr/include/c++/4.8/iostream:39:0,
from main.cpp:5:
/usr/include/c++/4.8/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = A]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
make: *** [main] Error 1
I get the same error if I make A a a class member:
class B {
A a; // <-- LOOK
std::ostream& operator<< (std::ostream& os) {
std::cout << a;
return os;
}
};
What gives?
First Case
A a();
does not construct an object. It declares a function. This parsing problem is known as The Most Vexing Parse.
A a();
std::cout << a;
works because a is converted to a bool in this case. See Why does pointer to int convert to void* but pointer to function convert to bool? why that works.
Second Case
A a;
std::cout << a;
does not work because of the way you have defined the operator<< function. You'll have to use
A a;
a << std::cout;
The operator<< function needs to be a non-member function in order to use:
A a;
std::cout << a;
See my answer to another SO post to understand why.

Trying to print vector of objects with overloading?

I'm working on a hash table program involving linear probing. I'm trying to print out the vector of Symbol class objects but I'm running into two errors every time I try to do it. I've posted these errors below:
LinearProbing.h: In instantiation of 'void HashTable<HashedObj>::print() [with HashedObj = Symbol]':
Driver.cpp:79:21: required from here
LinearProbing.h:82:4: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
In file included from /opt/local/include/gcc47/c++/iostream:40:0,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/ostream:600:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = HashTable<Symbol>::HashEntry]'
Here is where I'm trying to print the vector in the HashTable class...
class HashTable
{
///...
void print()
{
typename vector<HashEntry>::iterator vIter = array.begin;
while(vIter != array.end())
{
cout<< *vIter << "\n";
++vIter;
}
}
private:
vector<HashEntry> array;
};
And my overloading in the Symbol class...
friend ostream & operator <<(ostream & outstream, Symbol & symbol) //overloaded to print out the the HashTable
{
int num = symbol.type;
string name = symbol.data;
outstream << name << " : " << num << "\n";
return outstream;
}
Not sure what you're doing there but you have defined a vector of HashEntry and calling cout on HashEntry but your operator<< overload operates on Symbol instead.
The operator<< for class Symbol should look something like this
class Symbol {
private:
friend ostream& operator<<(ostream &os, const Symbol &s);
int type;
string data;
};
ostream& operator<<(ostream &os, const Symbol &s)
{
os << s.data << " : " << s.type;
return os;
}

Error when inserting string << overload C++

I am trying to overload the << operator on a class in C++. Whenever I insert a normal string, like the " " into the output stream I get compilation errors that I cannot make sense of. I have done this once before with no problems, so I am very confused.
friend std::ostream& operator<<(std::ostream& out, Variable v);
std::ostream& operator<<(std::ostream& out, Variable v) {
out << v.type;
out << " ";
out << v.name;
return out;
}
And here is the output:
src/Variable.cpp: In function 'std::ostream& operator<<(std::ostream&, Variable)':
src/Variable.cpp:35:9: error: no match for 'operator<<' in 'out << " "'
src/Variable.cpp:35:9: note: candidates are:
src/Variable.cpp:33:15: note: std::ostream& operator<<(std::ostream&, Variable)
src/Variable.cpp:33:15: note: no known conversion for argument 2 from 'const char [2]' to 'Variable'
In file included from /usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/string:54:0,
from src/../inc/Variable.h:4,
from src/Variable.cpp:1:
/usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/bits/basic_string.h:2750:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
/usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/bits/basic_string.h:2750:5: note: template argument deduction/substitution failed:
src/Variable.cpp:35:9: note: mismatched types 'const std::basic_string<_CharT, _Traits, _Alloc>' and 'const char [2]'
make: *** [bin/Variable.o] Error 1
Derp. I did not include iostream. However, this does not make much sense to me... since it worked whenever I did not add a string to the ostream. I would think that the compiler would not be able to find ostream at all, and would complain about that
#include <utility>
#include <iostream>
template <typename T1, typename T2>
std::ostream& operator<< (std::ostream& out, const std::pair<T1, T2>& v)
{
out << v.first;
out << " ";
out << v.second << std::endl;
return out;
}
int main()
{
std::pair<int, int> a = std::make_pair(12, 124);
std::cout << a << std::endl;
return EXIT_SUCCESS;
}
Its an example how to declare and implement an operator <<
I will show your solution in code
#include <iostream>
#include <string>
/* our custom class */
class Developer
{
public:
Developer(const std::string& name, int age) :
m_name(name),
m_age(age)
{}
const std::string& name() const { return m_name; }
int age() const { return m_age; }
private:
std::string m_name;
int m_age;
};
/* overloaded operator<< for output of custom class Developer */
std::ostream& operator<< (std::ostream& stream, const Developer& developer)
{
stream << "Developer name:\t" << developer.name() << std::endl;
stream << "Developer age:\t" << developer.age() << std::endl;
return stream;
}
/* test custom operator<< for class Developer */
int main(int argc, const char** argv)
{
Developer max("Maxim", 23);
std::cout << max;
return 0;
}

Conversion operators

This code is not compilable.
I can't find why in standard. Can someone explain?
#include <iostream>
#include <string>
template<typename T>
class S
{
public:
explicit S(const std::string& s_):s(s_)
{
}
std::ostream& print(std::ostream& os) const
{
os << s << std::endl;
return os;
}
private:
std::string s;
};
template<typename T>
std::ostream& operator << (std::ostream& os, const S<T>& obj)
{
return obj.print(os);
}
/*template<>
std::ostream& operator << <std::string> (std::ostream& os, const S<std::string>& obj)
{
return obj.print(os);
}*/
class Test
{
public:
explicit Test(const std::string& s_):s(s_)
{
}
//operator std::string() const { return s; }
operator S<std::string>() const { return S<std::string>(s); }
private:
std::string s;
};
int main()
{
Test t("Hello");
std::cout << t << std::endl;
}
Compiler output:
source.cpp: In function 'int main()':
source.cpp:47:17: error: no match for 'operator<<' in 'std::cout << t'
source.cpp:47:17: note: candidates are:
In file included from include/c++/4.7.1/iostream:40:0,
from source.cpp:1:
include/c++/4.7.1/ostream:106:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
include/c++/4.7.1/ostream:106:7: note: no known conversion for argument 1 from 'Test' to 'std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}'
....
Thats because no conversions, except for array-to-pointer, function-to-pointer, lvalue-to-rvalue and top-level const/volatile removal (cf. c++11 or c++03, 14.8.2.1), are considered when matching a template function. Specifically, your user-defined conversion operator Test -> S<string> is not considered when deducing T for your operator<< overload, and that fails.
To make this universal overload work, you must do all the work at the receiving side:
template <class T>
typename enable_if<is_S<T>::value, ostream&>::type operator <<(ostream&, const T&);
That overload would take any T, if it weren't for the enable_if (it would be unfortunate, since we don't want it to interfere with other operator<< overloads). is_S would be a traits type that would tell you that T is in fact S<...>.
Plus, there's no way the compiler can guess (or at least it doesn't try) that you intended to convert Test to a S<string> and not S<void> or whatever (this conversion could be enabled by eg. a converting constructor in S). So you have to specify that
Test is (convertible to) an S too
the template parameter of S, when converting a Test, is string
template <class T>
struct is_S {
static const bool value = false;
};
template <class T>
struct is_S<S<T>> {
static const bool value = true;
typedef T T_type;
};
template <>
struct is_S<Test> {
static const bool value = true;
typedef string T_type;
};
You will have to convert the T to the correct S manually in the operator<< overload (eg. S<typename is_S<T>::T_type> s = t, or, if you want to avoid unnecessary copying, const S<typename is_S<T>::T_type> &s = t).
The first paragraph of #jpalecek's answer explains what the issue is. If you need a workaround, you could add a declaration like:
inline std::ostream& operator<< (std::ostream& os, const S<std::string>& s)
{ return operator<< <> (os, s); }
Since that overload is not a template, implicit conversions to S<std::string> will be considered.
But I can't see any way to do this for all types S<T>...

A way to print of map of multimaps?

I'm trying to overload operator<<, and it drove me crazy:
std::ostream& operator<<(std::ostream & lhs, TuringMachine::TRTable& rhs){
for(auto& statePtr : rhs){
lhs << statePtr.first->getLabel().toStdString();
for(auto& charPtr: statePtr.second){
//lhs << '\t';
lhs << charPtr.first.toAscii() ;
//lhs << 'b ';
lhs << charPtr.second.getState().getLabel().toStdString() << std::endl;
}
}
return lhs;
}
TRTable is a typedeffor std::map<State*, std::multimap<QChar, Transition>>. Statehas its label as a QString hence the call to .toStdString().
In another class I call std::cout << machine->table << std::endl; with machine beeing a TuringMachine* and this gives me
error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
What am I doing wrong? Why &&?
EDIT: using g++ 4.6 and -std=c++0x
In which namespace did you declare the operator<<? Since TRTable is a typedef ADL does not apply, so the operator<< is searched only in namespace std by ADL, since this is where the actual class is defined. So you might have to use the namespace where you defined the operator<< when you want to use it.
lhs should have type std::ostream &. No const.
rhs should be const TuringMachine::TRTable&:
std::ostream& operator<<(std::ostream& lhs, const TuringMachine::TRTable& rhs)