this compiles :-)
string name;
name = 1;
this does not:
string name = 1;
any thoughts?
I know that this is wrong. . . that is not the point. The first gives a smiley face.
The first compiles because the assignment operator is called what has one signature of "string& operator= ( char c )" and the compiler can convert 1 into a char.
The second won't compile because it calls the copy constructor which has no compatible signature.
The second example is really initialization rather than assignment, i. e. it calls a constructor rather than operator=. Evidently class string does not have a constructor that takes an integer as an argument, but it's assignment operator is ok with it. And the reason you get a smiley face is that it is the character with the ASCII value of 1.
By the way, this is not specific to Visual Studio. Any C++ compiler should behave the same way.
Not to do with the question, but why don't you (and many others) post compilable code. Would :
#include <string>
using namespace std;
int main() {
string name;
name = 1;
string name2 = 1;
}
have been too much to ask for? Given that, we can see that "string" actually refers to std::string and not some random class.
Related
I'm going through Mr. Stroustrup's "A Tour of C++" book. In section 9.3 String Views, the author gives the following example:
string cat(string_view sv1, string_view sv2)
{
string res(sv1.length()+sv2.length());
char *p = &res[0];
for (char c : sv1) // one way to copy
*p++ = c;
copy(sv2.begin(),sv2.end(),p); // another way
return res;
}
When I try to compile this function, I get following error as std::string class doesn't provide any constructor which takes a single int parameter.
error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(std::basic_string_view<char>::size_type)' 11 | string res(sv1.length()+sv2.length());
I checked the Errata for 2nd printing of A Tour of C++ but there is no mention of this issue.
Is this a bug in the example provide or else I'm missing something else?
Is this a bug in the example provide or else I'm missing something else?
Yes this is an erratum in the book as std::string doesn't have a constructor that has only one parameter of type int(or convertible to int).
Instead it has a constructor std::string::string(size_type, char) that can take a char as the second argument. In particular, from std::string:
fill (6) string (size_t n, char c);
(6) fill constructor:
Fills the string with n consecutive copies of character c.
Thus to resolve the erratum, we should pass a second argument as shown below:
string res(sv1.length()+sv2.length(), '\0');
I've used cpp for quite a while, I was known that we cannot add string and numbers(as + operator is not overloaded for that). But , I saw a code like this.
#include <iostream>
using namespace std;
int main() {
string a = "";
a += 97;
cout << a;
}
this outputs 'a' and I also tried this.
string a ="";
a=a+97;
The second code gives a compilation error(as invalid args to + operator, std::string and int).
I don't want to concatenate the string and number.
What is the difference? Why does one work but not the other?
I was expecting that a+=97 is the same as a=a+97 but it appears to be different.
The first snippet works because std::string overrides operator+= to append a character to a string. 97 is the ASCII code for 'a', so the result is "a".
The second snippet does not work because there is no + operator defined that accepts a std::string and an int, and no conversion constructor to make a std::string out of an int or char. There two overloads of the + operator that take a char, but the compiler cannot tell which one to use. The match is ambiguous, so an error is reported.
The following piece of code compiles and runs without errors and with the expected output:
#include <string>
#include <iostream>
using namespace std;
string getString()
{
char s[] = "Hello world!";
return s;
}
int main()
{
cout << getString() << endl;
}
My question is, will this always work? Ordinarily if you return a C-string that was declared locally you can run into some undefined behavior, but in this case is that still a problem since it is run through the string constructor and (presumably) copied into dynamic memory?
return s;
That line is equivalent to:
return std::string(s);
And that will make a copy of the string, so it's fine.
reference: http://en.cppreference.com/w/cpp/string/basic_string/basic_string (constructor #5)
Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s.
Edit: One more detail. You mention
copied into dynamic memory?
And the answer is maybe, perhaps, it doesn't really matter.
The semantics provided by std::string make no specification towards this, it just guarantees that it can be copied/moved around and accessed in a consistent matter. How it acheives this is up to the library implementor.
In fact, popular implementations of std::string use something called the "Small String Optimization". Where strings under a certain length are stored within the string object itself.
I would guess that the last two lines in this code should compile.
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
My guess would be wrong, though. One line compiles and the other does not.
The AddMember method has several variants as documented here, but beyond that... why is the return of .c_str() not equivalent to a string literal?
My understanding was that where ever a string literal was accepted, you could pass string::c_str() and it should work.
PS: I'm compiling with VC++ 2010.
EDIT:
The lack of #include <string> is not the problem. It's already included by document.h
This is the error:
error C2664: 'rapidjson::GenericValue<Encoding> &rapidjson::GenericValue<Encoding>::AddMember(rapidjson::GenericValue<Encoding> &,rapidjson::GenericValue<Encoding> &,Allocator &)'
: cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue<Encoding> &'
with
[
Encoding=rapidjson::UTF8<>,
Allocator=rapidjson::MemoryPoolAllocator<>
]
and
[
Encoding=rapidjson::UTF8<>
]
EDIT2:
Please ignore the fact that .c_str() is called on a temporal value. This example is just meant to show the compile error. The actual code uses a string variable.
EDIT3:
Alternate version of the code:
string str("value") ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //compiles
obj.AddMember("key", str, doc.GetAllocator()) ; // does not compile
obj.AddMember("key", str.c_str(), doc.GetAllocator()) ; // does not compile
The std::string::c_str() method returns a char const*. The type of a string literal is char const[N] where N is the number of characters in the string (including the null terminator). Correspondingly, the result of c_str() can not be used in all places where a string literal can be used!
I'd be surprised if the interface you are trying to call requires a char array, though. That is, in your use it should work. It is more likely that you need to include <string>.
even if this code compiled:
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator());
You cannot guarantee that it is safe.
The const char* returned by std::string::c_str() will be valid until the end of this statement.
If the AddMember method stores a copy of the string itself, all well and good. If it stores a pointer then you're doomed. You need knowledge of the inner workings of AddMember before you can reason about the correctness of your code.
I suspect the authors have already thought of this and have constructed overloads that demand that you either send in a std::string object (or equivalent) or a string literal reference (template<std::size_t N> void AddMember(const char (&str)[N]))
Even if this is not what they had in mind, they might be looking to protect you from yourself, in case you inadvertently send in an invalid pointer.
While seemingly an inconvenience, this compile time error indicates a possibly-faulty program. It's a tribute to the library's authors. Because compile time errors are a gazillion times more useful than runtime errors.
Looking at the documentation you linked to, it seems like you are trying to call the overload of AddMember taking two StringRefTypes (and an Allocator). StringRefType is a typedef for GenericStringRef<Ch>, which has two overloaded constructors taking a single argument:
template<SizeType N>
GenericStringRef(const CharType(&str)[N]) RAPIDJSON_NOEXCEPT;
explicit GenericStringRef(const CharType *str);
When you pass a string literal, the type is const char[N], where N is the length of the string + 1 (for the null terminator). This can be implicitly converted to a GenericStringRef<Ch> using the first constructor overload. However, std::string::c_str() returns a const char*, which cannot be converted implicitly to a GenericStringRef<Ch>, because the second constructor overload is declared explicit.
The error message you get from the compiler is caused by it choosing another overload of AddMember which is a closer match.
Re
” why is the return of .c_str() not equivalent to a string literal
A string literal is a zero-terminated string in an array with size known at compile time.
c_str() produces a pointer to (the first item in) a zero-terminated string in an array with size known only at run-time.
Usually a string literal expression will be used in a context where the expression decays to pointer to first item, but in some special cases it does not decays. These cases include
binding to a reference to array,
using the sizeof operator, and
forming a larger literal by compile time concatenation of string literals (simply writing them in order).
I think that's an exhaustive list.
The error message you cite,
” cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue &
… does not match your presented code
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key1", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
Nowhere in this code is there a three character long string literal.
Hence the claims that “this compiles” and “this does not compile”, are not very trustworthy.
You
should have quoted the actual error message and actual code (at least one of them is not what you had when you compiled), and
should have quoted the documentation of the function you're calling.
Also, note that the actual argument that compiler reacts to in the quoted diagnostic, is a literal or an array declared as such, not a c_str() call.
#include <iostream>
#include <string>
using namespace std;
std::string dispCard(int card)
{
string textCard = "help";
//cout << textCard;
system("pause");
return textCard;
}
int main()
{
// Using this area to test functions for now
cout << dispCard(14);
return 0;
}
Uncommenting the cout line actually does display the value. But I cannot return the value in the string.
Honestly, I have no idea why this isn't working. I initially just wanted to use "char" but that doesn't work for some reason.
Visual Studio didn't like:
char test;
test = "help";
It underlined the "=".
For now, I just want to return a string value from a function. There's more that I need it to do, but this is the main issue right now.
Uncommenting the cout line actually does display the string. But not returning the string.
Your program both prints and returns the string, printing it again in main. The only problems I can see with your program are:
You are using system("pause") for no reason.
You are not consistent with the use of either the std:: prefix or importing the namespace. On this regard I highly suggest the std:: prefix.
You are not using the function argument.
I initially just wanted to use "char" but that doesn't work for some reason.
Well, char, as the name suggests, can only store 1 characters. In:
char test = "help";
you are trying to assign 5 characters (4 + \0) to an objects who's size can only store 1. That's the reason why your compiler complained.
I think you need to pass an int to your function and get it back in string form. To do this conversion you need something like this:
std::ostringstream stm;
stm << yourIntValue;
std::string s(stm.str());
or this:
char bf[100];
sprintf(bf, "%d", yourIntValue);
std::string s(bf);
If you put this snippet in a function then you can also accept an int parameter, convert it to a std::string and return the std::string as others have shown.
What you need to do is to declare return type of function as std::string and then return either a string object, something that can implicitly be converted to string object or something that explicitly constructs string object.
Example:
std::string foo(){
return "idkfa"; //return C-style string -> implicitly convertible to string
return {"idkfa"}; // direct initialization of returning std::string
return std::string("idkfa"); //return explicitly constructed std::string object
}
Also note that C-style strings are of type char* (C-style strings are basically an array of chars, with last element being \0, that is 0).
Your code works perfectly fine, though the the system("pause") is totally redundant and pointless and should be removed. It may in fact be confusing you.