STL Push_back string in vector - c++

I am trying to push a string in a string vector, like below
void Node::set_val(string &val)
{
this->val.push_back(val);
}
But when I try to call it as below
Obj.set_val("10h;");
I get the below error,
error: no matching function for call to 'Node::set_val(const char [5])'
I assumed that the string in " " is same as string in c++, Why do I get such an error? What has to be changed below?

You are taking in a std::string by non-const reference. Non-const references cannot bind to rvalues, like "10h;", so you can't pass literals in to that function.
If you aren't going to modify the argument, you should take your argument by reference-to-const:
void Node::set_val(const string &val)
// ^^^^^
This way, a temporary std::string will be constructed from your const char[5] and passed in to set_val.
You could improve this by taking in the string by value and moveing it into the vector:
void Node::set_val(string val)
{
this->val.push_back(std::move(val));
}
This prevents you from making some unnecessary copies.

So in C++, const char* is implicitly convertible to std::string because std::string has a (non-explicit) constructor that takes const char*. So what the compiler tries here is to create a temporary std::string object for your function call, like so:
Node.set_val(std::string("10h;"));
However, since you declared the parameter of set_val to be a non-const reference to a std::string, the compiler can't make this conversion work due to the fact that temporary objects can't be bound to non-const references.
There are three ways to make this work, depending on what you want to achieve:
void Node::set_val(const std::string& val) {}
void Node::set_val(std::string val) {}
void Node::set_val(std::string&& val) {}
All will compile (the last one requires C++11 or higher), but seeing your use case, I would recommend to use the second or third one. For an explanation why, try reading a little bit about move semantics in C++11.
The important thing to take away here is that const char* implicitly converts to std::string by creating a temporary object, and temporary objects can't be passed to functions taking non-const references.

You are passing "10h;" which is a const char array.
Fix it by passing a string: Obj.set_val(string("10h")); and edit function to take a string by value:
void Node::set_val(string val) { /* */ }
Or maybe better, edit your function to take a const string&:
void Node::set_val(const string &val) { /* */ }

Related

Correct way to use reference lvalues

My code is the following:
void parentheses (int n, string& str, int left, int right){
... irrelevant...
}
void solve(int n){
parentheses(n,"",0,0);
}
However, this will give me an error, telling me that cannot bind non-const lvalue reference of type std::__cxx11::string& ... to an rvalue of type ‘std::__cxx11::string. In this case, if I still want to pass the string in as a reference, how should I modify my functions? I don't want to make them const because I want to functions to modify the original string, and I want them to be & precisely because I want to edit their values.
The function parentheses expects an lvalue in the std::string parameter, i.e. a named variable. However, you have supplied an rvalue (temporary) in this call:
parentheses(n,"",0,0);
An empty string object is created and passed to parentheses. You can avoid this problem by changing the definition of parentheses like so:
void parentheses (int n, const string& str, int left, int right)
Here str will bind to an rvalue/temporary, but you won't be able to change its value in the function. However, if you want to change the value of str you have to define a string variable and pass that to the function.
Example:
void solve(int n){
std::string str;
parentheses(n,str,0,0);
}
Note: no need to assign str to "" as a string is empty by default.
the function needs a memory to change, you didn't specify which.
declare a string to hold what you want to pass and where to get the output to.
string s = "";
and pass it to the function
I'm not really sure what the purpose is of passing "" by reference is, as any value put there will get lost.
Anyway, to answer your question, create a variable and pass it instead:
void solve(int n){
std::string tmp = "";
parentheses(n,tmp,0,0);
}
If you don't care about the value stored in tmp, you can just ignore it. But you need some type of variable there, even if you don't care about what gets eventually put there by the routine.
Your parentheses() function takes a non-const reference to a std::string object, so it expects an actual std::string object on the other side of the reference - an lvalue (something that can be assigned to).
But your solve() function is not passing a std::string object, it is passing a string literal instead. So the compiler creates a temporary std::string object - an rvalue - which then fails to bind to the reference, because a temporary object can't be bound to a non-const reference, only to a const reference. That is what the error message is telling you:
cannot bind non-const lvalue reference of type std::__cxx11::string& ... to an rvalue of type ‘std::__cxx11::string
solve() needs to explicitly create an actual std::string object to pass to parentheses():
void solve(int n){
std::string s = "";
parentheses(n,s,0,0);
}
If you want to change the values of your string for any string that is passed as a paramenter (lvalue, as well rvalue), just initialize a variable with the intended content and pass it to your function.
But if you want to treat lvalue strings diferently from rvalue strings, just overload your original function. i.e.:
void parentheses (int n, string& str, int left, int right){
... irrelevant... // change strings values as desired
}
void parentheses (int n, string&& str, int left, int right){
... irrelevant... // string as rvalue
}

Passing a returned string into a function as reference without assigning it to a string variable

I have a function defined as:
void func(string & str_alias)
{...}
And in my main function
int main()
{
string a;
func((a="Cat said: ")+"Meow");
}
The compiler would report that
no known conversion for argument 1 from ‘std::basic_string<char>’ to ‘std::string& {aka std::basic_string<char>&}’
Though I know if I change the main function into:
int main()
{
string a;
func(a=((a="Cat said: ")+"Meow"));
}
The code would pass with no issues. But I still wonder why the returned string cannot be passed to the function as a reference. Why do I have to assign it to another string variable?
Thanks.
As long you don't need to change the passed reference, you could easily avoid this by changing your function signature to
void func(const string & str_alias)
// ^^^^^
{...}
and simply call
func(string("Cat said: ") + "Meow");
(see live demo)
If you'll need to change the reference parameter, you must have an lvalue to be modified. Nevertheless writing
func(a=string("Cat said: ")+"Meow");
is sufficient (see the live demo).
If you make it take const reference to std::string, it should compile.
This is because the last thing you do in the first function call is calling std::string operator+(const std::string&, const char*), which as you see returns std::string, not reference, and since it not stored anywhere, it is rvalue, which can't be bound to lvalue-reference.
The second example compiles, because the last thing you do is assign it to the variable a, which calls std::string& operator=(const char*), which as you can see returns reference, so it can be used as non-const reference by itself.
Thanks to 0x499602D2 for correction.

Any way to shorten String type in C++?

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.

Why it does not work when I pass reference to this function?

The code below:
void test(string &s){ // if the argument is "string s", it works
return test(s+',');
}
The compiler reports cannot find the function: test(std::basic_string).
I think the compiler would create a temporary string (== s+','), and I can pass its reference.
But it seems I am wrong. I do not know why I cannot pass the reference of this temporary string.
You can't bind a temporary to a non-constant reference. You could either take the argument by const reference (or, as you point out, by value)
void test(string const & s){ // or string s
return test(s+',');
}
or use a named variable rather than a temporary
void test(string & s){
std::string s2 = s + ',';
return test(s2);
}
As noted, at great length, in the comments, this code has undefined runtime behaviour and shouldn't be used in "real" code; it's purpose is just a minimal example of how to fix the observed compilation error
make it const:
void test(const std::string &s){ // if the argument is "string s", it works
return test(s+',');
}
But first you should have seen this question String Concatenation
concatenating strings using "+" in c++
Alternative Solution
void test(string &s)
{
s.append(",");
return test(s);
}
Standard C++ does not allow a non-const lvalue reference to be bound to an rvalue. In your example, the result of the expression s+',' is a temporary and thus an rvalue, so the compiler is required to discard the overload of test expecting an lvalue reference, leaving it no overload available to call. That's why it complains about not being able to find the function test.
To solve this issue you have to provide an overload whose parameter may be bound to an rvalue. As you realized yourself, expecting an argument by-copy works, but it may imply unnecessary overhead by calling copy/move-ctors. A better option would be to expect the argument by reference. Since const lvalue references may be bound to rvalues, declaring the function as follows solves the problem.
void test(std::string const& s)

how does std::string manages this trick?

i just wrote a function:
void doSomeStuffWithTheString(const std::string& value) {
...
std::string v = value;
std::cout << value.c_str();
...
}
but then i call this with
doSomeStuffWithTheString("foo");
and it works. So i would have thought that this to work (a const char* to initialise a implicit instance of std::string) the value would have to be passed by value, but in this case is passed by (const) reference.
Is by any chance a implicit temporal std::string instantiated from const char* when the reference is const? if not, then how this possibly work?
EDIT
what happens if the function is overloaded with
void doSomeStuffWithTheString(const char* value);
which one will choose the compiler?
The std::string type has an implicit conversion (via constructor) from const char*. This is what allows the string literal "foo" to convert to std::string. This results in a temporary value. In C++ it's legal to have a const & to a temporary value and hence this all holds together.
It's possible to replicate this trick using your own custom types in C++.
class Example {
public:
Example(const char* pValue) {}
};
void Method(const Example& e) {
...
}
Method("foo");
Yes, a temporary std::string is constructed from the string literal.
Exactly, using std::string default constructor
"the value would have to be passed by value, but in this case is passed by (const) reference."
There is a C++ feature where it is possible to pass a temporary value (in this case, a temporary std::string implicitly converted from the const char *) to an argument of const-reference (in this case, const std::string &) type.