How does stringstream work when you do this:
stringstream ss;
ss << "123" << "abc";
Does it create a throwaway "123abc" string or does it do both operations consecutively to the stringstream?
I would like to replicate that functionality but no overload I do seems to work with two parameters like the above code...
It's the equivalent of doing two seperate function calls of the << operator:
(ss.operator<<("123")).operator<<("abc")
so yes, it does both operations "consecutively".
Actually it is equivalent to this:
std::operator<<(std::operator<<(ss, "123"), "abc");
Note that there is no member function which takes const char* as argument. It is a non-member function, and ss is passed to it as first argument and const char* is passed as second argument. The function returns std::ostream& which then passed to it again. It is more like this:
print( print (ss, "123"), "abc"); //just for clarity
which means there are two function calls. Replace print with std::operator<<. Everything will be clear now.
Hope that helps.
The other answer which says this:
(ss.operator<<("123")).operator<<("abc") //copied from other answer (wrong)
is wrong! It is wrong because it assumes that operator<< which takes const char* as argument is a member function which is not true!
std::stringstream::operator<<(const char*) returns a std::stringstream&.
This technique lets you "chain" it.
This is not quite true -- but it is pretty much equivalent to the truth for your purposes.
A slightly more accurate statement is that std::stringstream& operator<<(std::stringstream&, const char*) can be chained.
An even more accurate statement is that ostream& operator<<(ostream&, const char*) exists, and std::stringstream is an ostream, then overload resolution on << calls it.
Related
Everybody knows that you can't concatenate 2 string literals using the + operator.
#include <iostream>
int main() {
std::cout << "hello " + "world";
}
// Error
What's happening here is that you are trying to add 2 char* which is an error. You can however add a string literal to a std::string.
#include <iostream>
int main() {
std::string s = "hello ";
std::cout << s + "world";
}
// Fine, prints hello world
But what I found is that the below code is also valid.
#include <iostream>
int main() {
std::string s = "world";
std::cout << "hello " + s;
}
// Fine, prints hello world
I would imagine in the above example that you are trying to add a std::string to a char* but it works fine. I think it may just be using the std::string overload of the + operator. My question is what exactly is happening here and how does the operator decide which overload to use in a situation such as with 2 different classes with perfectly valid overloads being added together.
What's happening here is that you are trying to add 2 char* which is an error.
To be a bit more correct, you're trying to add two arrays, each of which decay to const char*.
My question is what exactly is happening here
You're using these overloads:
std::string
operator+(const std::string& lhs, const char* rhs);
std::string
operator+(const char* lhs, const std::string& rhs);
how does the operator decide which overload to use
It uses the same overload resolution as normal functions do. The complete and precise description won't fit within this answer since overload resolution is quite complex.
In short: There is a list of all functions by the same name. This is the overload set. If all arguments (operands in case of operator overload) can be converted to the formal parameters of the function, then that function is a viable candidate for the overload resolution. The candidates are ranked by a set of rules. Candidate requiring "less" conversion is ranked higher. If one candidate is unambiguously the most highly ranked candidate, then that overload will be called; otherwise there is an error.
Operator precedence : + has higher rank than <<, hence the line is parsed as:
(std::cout << ("hello " + s) );
And operator+(const char*,const std::string&) is the one on place 4 here: https://en.cppreference.com/w/cpp/string/basic_string/operator%2B.
Maybe you are a little surprised, because often operators are member functions and that implies that the left operand would need to be the std::string. However, thats not always the case. Operators can be free functions.
I have simple lines of code, where I am using insertion operator << to show hello world string. If I use a operator b then it should result to a.operator(b); I try to do same thing with insertion operator and in output I got address of string, rather than actual string.
std::cout<<"Hello world"<<std::endl;
std::cout.operator<<("Hello world").operator<<(std::endl);
Output:
Hello world
0120CC74
I am using Visual Studio.
Does my operator conversion has any problem?
std::cout<<"Hello world"<<std::endl;
use overloaded output operator for const char*, that is free function, not member function.
std::cout.operator<<("Hello world").operator<<(std::endl);
use overloaded output operator for const void*, since const char* is implicitly convertible to const void*.
You can look at member overloads here and free overloads here
My bet is that member function operator for std::ostream(char*) is not overloaded.
If you look at ostream::operator<<, void* is best match and char* naturally gets converted to it, while global operator<<(std::basic_ostream), has exact overloads for char* types, which gets picked up.
Of course, they behave differently.
As the other answers say, the problem is that you are explicitly calling the member function operator <<, which is not overloaded for const char*.
To get the const char* overload, you need to call the free operator << function, which is appropriately overloaded:
operator<<(std::cout, "Hello World").operator<<(std::endl);
Similarly, there is no free function overload of operator << for writing an std::ostream& (*)(std::ostream&), so for std::endl you have to use the member function.
From this, we can see that you can not rewrite from the infix operator syntax (std::cout << ...) to function calling syntax (operator << (...)) without losing generality.
Let's say I have function foo(string& s). If I would get C string, foo(char* s), I would simply call the function as foo("bar").
I wonder if I can somehow do it in the C++ String?
Somehow to shorten this:
string v("bar");
foo(v)
I'm using Linux GCC C++.
It is not working because the argument has to be a const reference:
void foo( const std::string& s )
// ^^^^^
foo( "bar" ); // will work now
If you want foo to only read from the argument you should write foo(const string& s).
If you want foo to save the string somewhere (a class member..) you should write foo(string s).
Both versions allow you to write foo("bar"); which would't make any sense with a non const reference.
You could also try foo(string("bar")); to get your desired results, but since it is expecting a reference this wont work either.
So that means that your best bet is overloading for const char * to call the string method (this way you maintain only one method).
The std::string class does have an implicit conversion from const char*, so normally, passing a string literal into a function taking std::string works just fine.
Why it fails in your case is that the function takes its parameter as a non-const lvalue reference, and thus it requires an actual std::string lvalue to operate on.
If the function actually wants to take a non-const lvalue reference (i.e. it modifies the argument), you have to create an lvalue std::string and pass it (just like you do).
If the function does not modify the argument, change it to take by const-reference (const std::string&) or by value (std::string) instead; for both of these, passing an rvalue (like the std::string created by implicit conversion from const char*) will work and you can thus call the function with string literals.
Given these 2 functions that modify and return a string:
// modify the original string, and for convenience return a reference to it
std::string &modify( std::string &str )
{
// ...do something here to modify the string...
return str;
}
// make a copy of the string before modifying it
std::string modify( const std::string &str )
{
std::string s( str );
return modify( s ); // could this not call the "const" version again?
}
This code works for me using GCC g++, but I don't understand why/how. I'd be worried that 2nd function would call itself, leaving me with out-of-control recursion until the stack is exhausted. Is this guaranteed to work?
You have two overloaded functions:
std::string &modify( std::string &str )
std::string modify( const std::string &str )
What you're passing is a non const-qualified std::string. Therefore, the function that takes the non const-qualified argument is a better fit. If that didn't exist, the compiler could convert the non const-qualified string to a const-qualified string to make the call, but for function overloading a call that requires no conversion is a better fit than a call that requires a conversion.
return modify( s ); // could this not call the "const" version again?
No. It is not recursion. It would invoke the other overload whose parameter is std::string &.
It is because the type of the expression s is std::string & which matches with the parameter type of the other overloaded function.
In order to recurse, the argument at call-site needs to convert into std::string const &. But in your case, this conversion is unnecessary as there exists an overload which doesn't require conversion.
This isn't recursion, it's overloading. When you call the second function, the argument going into it is a constant string. Inside that function, you call the other function which takes a non-const string. What you're doing is stripping the const-ness of the string and a better way of doing that would be to use const_cast.
I'll just link to this other stackoverflow thread.
I'm trying to make a class, let's say MyClass, work under the following condition:
MyClass name = "everyone"; // Assigns "everyone" into a local string variable.
printf_s("Hello %s!", name); // Should output "Hello everyone!" without the quotes.
I've tried overloading operator const char*() as well as operator char*() but neither seem to do the trick.
If you overload it with operator const char*, you can explicitly cast it:
MyClass name = "everyone";
printf_s("Hello %s!", (const char*)name);
// prints "Hello everyone!"
And then it will behave properly. It doesn't work implicitly becase printf can take any type of parameter after the first one, so the compiler has no idea what to try to cast it to.
This assumes, of course, that operator const char* of your class returns the C-style string everyone.
As Tomalak Geret'kal noted in the comments, making your class implicitly castable to const char* could cause a lot of problems because it can cast itself without you knowing/wanting it to.
As Kerrek SB also pointed out, it's probably not worth making your class compatible with printf, since this is C++ after all. It would be better style to write an operator<< overload for ostream&s:
ostream& operator<<(ostream& rhs, const MyClass& c) {
rhs << c.name; // assuming the argument to the constructor
// is stored in the member variable name
return rhs;
}
MyClass name = "everyone";
cout << "Hello " << name << '!';
// prints "Hello everyone!"
You cannot "detect" the intention of being converted to a char const* when being passed into an ellipsis (...). Your object will just be put on the stack and you'll probably crash. This is different than if your object is passed in to a function that explicitly takes a char const*, in which case an implicit conversion operator can be triggered.
I would recommend going the same route as the standard library and rely as little as possible on implicit conversions. Instead, use a c_str() member or something.