<< operator vs. overloaded + operator for strings in C++ - c++

Is there is difference between the two following lines of code?
(Perhaps in efficiency or something of that nature?)
const std::string a = "a";
const std::string b = "b";
std::cout << a << " comes before " << b << "\n";
std::cout << a + " comes before " + b + "\n";

Yes:
The first line calls operator<< of std::cout (of type std::ostream). It prints each of its operands.
The second line calls operator+ of std::string, which creates multiple temporary std::string objects which then eventually call operator<< which prints them.
Prefer the first because it avoids temporary objects, and works better. Consider the situation were a and b have type int. The first version continues to work the second will no longer work.

Related

Why does + operator between string and int acts as substr

When trying to concatenate a string with an int (without using the std::to_string, just to see what happens), I saw that there was no compilation error but the actual result is quite strange.
I tried to search on cplusplus.com how the + operator is defined for string, but I couldn't find any definition of this operator between string and int.
The code used to test the concatenation is the following :
std::cout << "Test" + 3 << std::endl;
I was expecting a compilation error, but I simply got a t in the console, which surprised me a bit.
Why does this operator acts this way, and where is it defined?
Thank you for your answers.
You are not using string+ int, you are doing const char* + int, that's pointer arithmetics.
That's a pointer to "Test", you increment it by 3, which means the pointer points to the substring "t".
As already answered you have pointer arithmetic due to using string literal
To see what happens when you use std::string you need to either cast explicitly:
std::cout << std::string("Test") + 3 << std::endl;
or if you have C++14 or later to use operator ""s
using namespace std::string_literals;
std::cout << "Test"s + 3 << std::endl;
operator+ has a higher precedence than operator<<, so this statement:
std::cout << "Test" + 3 << std::endl;
Get treated by the compiler as if you had written this instead:
std::cout << ("Test" + 3) << std::endl;
"Test" is a string literal of type const char[5], which will decay into a pointer to the T character. So, adding +3 to "Test" performs pointer arithmetic, thus a const char* pointer that is pointing at the t character gets passed to operator<<, as if you had written code like this instead:
const char *ptr = "Test";
ptr = ptr + 3;
std::cout << ptr << std::endl;
Changing "Test" to a std::string won't work by default, either:
std::cout << std::string("Test") + 3 << std::endl;
Because there is no standard operator+ that allows an int to be added to a std::string (you would have to define your custom operator if you want that).
So, to fix this, you have two choices:
Convert the int to a std::string:
std::cout << "Test" + std::to_string(3) << std::endl;
use operator<< instead of operator+:
std::cout << "Test" << 3 << std::endl;

Overloaded chained operator<< buffering output [duplicate]

I have a function that takes an ostream reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
The output of this code is:
How are you?
Hello, world!0x601288
However, if I separate the chaining expressions into two statements, like this
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
then I at least get the proper order in the output, but still get a hex value:
Hello, world! How are you?
0x600ec8
I would like to understand what's going on here. Does a normal function take precedence over operator<<, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
The behavior of your code is unspecified as per the C++ Standard.
Explanation
The following (I removed std::endl for simplicity)
std::cout << "Hello, world!" << print( std::cout );
is equivalent to this:
operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));
which is a function call, passing two arguments:
First argument is : operator<<(std::cout, "Hello, World!")
Second argument is : print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).
Why hexadecimal output?
You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.
Try this:
void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;
It will print the same value for both. For example, this example at ideone prints this:
0x804a044
0x804a044
Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.
Hope that helps.
What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
No matter how you write print().
However this is well-defined:
print(std::cout) << X << Y << Z; //well-defined behaviour!
The reason is that your print() function will be evaluated before the rest of the statement and return a reference to cout which is then actually printed as a pointer (cout << cout). This order of evaluation is actually unspecified behavior, but seems to be the case with your compiler.
As for defining a stream aware "function" that actually has defined behavior with the same functionality, this would work;
#include <iostream>
template <class charT, class traits>
std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print << std::endl;
}
See also this answer for a little more detail on what "unspecified" actually means in this case.
Hexadecimal Output
Before C++11, the class std::ostream has a conversion function to void*. Since your print function returns std::ostream&, when evaluating std::cout << print(...), the returned std::ostream lvalue will be implicitly converted to void* and then be outputted as a pointer value. This is why there is a hexadecimal output.
Since C++11, this conversion function is replaced by an explicit conversion function to bool, so trying to output an std::ostream object becomes ill-formed.
Evaluation Order
Before C++17, overloaded operator is considered a function call for analyzing evaluation order, and evaluation order of different arguments of a function call is unspecified. So it is not strange that the print function is evaluated firstly, which causes How are you? is outputted firstly.
Since C++17, the evaluation order of operands of operator << is strictly from left to right, and operands of overloaded operator share the same evaluation order as those of the bulit-in one (see more details here). So your program will always get the output (assume print returns something able to be outputted)
Hello, world! How are you?
something returned by print
LIVE EXAMPLE
In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl it's undefined whether std::cout << "Hello, world!" happens before or after print( std::cout ). That's why the order may not be what you expect.
The hex value comes from the fact that you're also doing std::cout << std::cout (print returns std::cout which is fed into the << chain). The right hand std::cout is converted to a void * and that's printed to the output.
This would work, to combine print with << and control the order:
print( std::cout << "Hello, world!" ) << std::endl;
Or, if you want a function that's called with <<, see Joachim's answer.

why return reference to ostream object in member function for serialization [duplicate]

This question already has answers here:
Why we need to return reference to istream/ostream while overloading >> and << operators?
(4 answers)
Closed 5 years ago.
//using namespace std;
Here's the following piece of code
ostream& write(ostream& os) const {
os << getRe() << "j " << getIm();
return os;
}
This is a member function in a class representing complex numbers ("PComplex), which is derived from an abstract class ("Serializable"). (Implementation of pure virtual function).
My main question is why do we need to return a reference to an ostream object? Why not void?
Returning an ostream& object allows us to chain a bunch of operators togeather.
Consider this statement
cout << "Hello " << "World";
This is actually two calls to ostream& operator<<(ostream& os, const char* c). If we consider the order of execution, we get:
(cout << "Hello ") << "World";
This function accepts cout on the left and "Hello " on the right. It prints the contents of the right hand-side to the console, then it returns cout. We we consider what's left after the first step we get this:
(cout) << "World";
Now we take the brackets away and get:
cout << "World;
This one is much easier to deal with. Now we call the function again to print `"World" and return the cout again, which we will simply not do anything with.
If we returned void instead of ostream&, then (cout << "Hello ") would reduce to (void). That would leave us with:
(void) << "World";
This doesn't match any overloads and so we would then get an error. While the (cout << "Hello ") would still work, we wouldn't be able to chain << "World" on the same line.

ostream chaining, output order

I have a function that takes an ostream reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
The output of this code is:
How are you?
Hello, world!0x601288
However, if I separate the chaining expressions into two statements, like this
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
then I at least get the proper order in the output, but still get a hex value:
Hello, world! How are you?
0x600ec8
I would like to understand what's going on here. Does a normal function take precedence over operator<<, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
The behavior of your code is unspecified as per the C++ Standard.
Explanation
The following (I removed std::endl for simplicity)
std::cout << "Hello, world!" << print( std::cout );
is equivalent to this:
operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));
which is a function call, passing two arguments:
First argument is : operator<<(std::cout, "Hello, World!")
Second argument is : print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).
Why hexadecimal output?
You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.
Try this:
void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;
It will print the same value for both. For example, this example at ideone prints this:
0x804a044
0x804a044
Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.
Hope that helps.
What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
No matter how you write print().
However this is well-defined:
print(std::cout) << X << Y << Z; //well-defined behaviour!
The reason is that your print() function will be evaluated before the rest of the statement and return a reference to cout which is then actually printed as a pointer (cout << cout). This order of evaluation is actually unspecified behavior, but seems to be the case with your compiler.
As for defining a stream aware "function" that actually has defined behavior with the same functionality, this would work;
#include <iostream>
template <class charT, class traits>
std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print << std::endl;
}
See also this answer for a little more detail on what "unspecified" actually means in this case.
Hexadecimal Output
Before C++11, the class std::ostream has a conversion function to void*. Since your print function returns std::ostream&, when evaluating std::cout << print(...), the returned std::ostream lvalue will be implicitly converted to void* and then be outputted as a pointer value. This is why there is a hexadecimal output.
Since C++11, this conversion function is replaced by an explicit conversion function to bool, so trying to output an std::ostream object becomes ill-formed.
Evaluation Order
Before C++17, overloaded operator is considered a function call for analyzing evaluation order, and evaluation order of different arguments of a function call is unspecified. So it is not strange that the print function is evaluated firstly, which causes How are you? is outputted firstly.
Since C++17, the evaluation order of operands of operator << is strictly from left to right, and operands of overloaded operator share the same evaluation order as those of the bulit-in one (see more details here). So your program will always get the output (assume print returns something able to be outputted)
Hello, world! How are you?
something returned by print
LIVE EXAMPLE
In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl it's undefined whether std::cout << "Hello, world!" happens before or after print( std::cout ). That's why the order may not be what you expect.
The hex value comes from the fact that you're also doing std::cout << std::cout (print returns std::cout which is fed into the << chain). The right hand std::cout is converted to a void * and that's printed to the output.
This would work, to combine print with << and control the order:
print( std::cout << "Hello, world!" ) << std::endl;
Or, if you want a function that's called with <<, see Joachim's answer.

Overloading << operator in C++

I want to overload << operator in a Line class so I can print an object using cout like this:
cout << myLineObject << endl;
but this is not working:
class Line{
public:
float m;
float b;
string operator << (Line &line){return ("y = " + line.m + "x + " + line.b);};
};
I get:
Invalid operands of types 'const char [5]' and 'float' to binary 'operator+'
I also tried with stringstream but I get even more errors. What is the correct way of doing this?
Thanks ;)
The correct way is listed everywhere overloading << is discussed, and you've managed to miss pretty much all of it.
The standard declaration is ostream & operator<<(ostream & s, const & Line l); It cannot be a member function, and it needs to return a reference to the ostream so that you can chain << as normal.
The definition, in your case, would be something like
ostream & operator<<(ostream & s, const & Line l)
{
return s << "y = " << l.m << "x + " << l.b;
}
Note that you return the incoming ostream, and print what you like using the << operator rather than using the + operator. It's pretty simple if you follow this
form.
In this case, the data members are public (which is not a good idea in general),
so there's no access problems. If you need to get inaccessible values (because
they're private and not exposed in the public interface), you'll need to declare
the operator to be a friend in the class definition.
operator<< has to be a non-member function, since the stream is the left-hand argument. In your case, since the data members are public, it can be implemented outside the class:
std::ostream& operator<<(std::ostream& stream, const Line& line)
{
return stream << "y = " << line.m << " x = " << line.b;
}
Googled this one, looks fine:
Overloading <<
Basically, when overloading << operator for IO, your function should look like this:
friend ostream& operator<<(ostream& output, const YourClassHere& p);
Notice, that operator<< is not a class member, but a external function (which can be friend if you need it to be). Such function should use output to write to it and then return it, so you can chain it.
The error here is nothing to do with the operator overloading, though once resolved you may have more questions on that. This error happens because there is no operator+ defined that takes arguments of const char[5] and float. Since you are trying to concatenate the string forms of those four args
"y = " + line.m + "x + " + line.b
you have to do this in a way the compiler can understand e.g.
ostringstream concat;
concat << string("y = ") << line.m << string("x + ") << line.b;
return concat.str();
Once you get past this, you can work on your << overloading logic.
You can do this way:
class Line{
public:
float m;
float b;
friend ostream& operator<< (ostream& out, Line& object) {
out << object.m << endl;
out << object.b << endl;
return out;
}
};
Then you can do:
cout << your_Line_object << endl;
Other have explained the correct way. I figured I'd mention what you are doing wrong.
You define an operator which takes two Line objects:
Line a;
Line b;
string c = a << b;
// c would have the string values for line b
// the values of line a would be ignored.
Of course, that's not the error you are seeing. That's caused by the line "y = " + line.m. "y = " is a char[5]. amd line.m is a float, and there is no operator+ which takes those two (This ain't Basic -- or C#).
The problem is that C++ has no easy way to "add" non-string values to a string. Which is why we use the convention of cout <<.