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');
Related
I'm getting these two errors in my code:
Error C3867 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str': non-standard syntax; use '&' to create a pointer to member 59
Error C2661 'Product::Product': no overloaded function takes 2 arguments 59
It seems like when I'm trying to call my non-default constructor it's only getting 2 arguments even though I'm trying to pass it 4. This is just speculation, but I suspect maybe I need to add some NULL checkers or something? but I don't see how any of the arguments I'm passing it could be NULL so I'm stuck.
Here's my declaration and definition for my non-default constructor:
Product(bool restocking, string name, int quantity, double price); //Declaration
Product::Product(bool restocking, string name, int quantity, double price):InventoryItem(restocking), quantity_(quantity), price_(price) { } //Definition
Product is a derived from InventoryItem
Here's the troublesome piece of code:
void InventorySystem::BuildInventory(void) {
int i{ 0 };
string name_buffer;
string quantity_buffer;
string price_buffer;
ifstream fin("in_inventory.txt");
if (fin) {
while (getline(fin, name_buffer, ';') && i < g_kMaxArray) {
getline(fin, quantity_buffer, ';');
getline(fin, price_buffer, '\n');
p_item_list_[i] = new Product(false, name_buffer, atoi(quantity_buffer.c_str), atof(price_buffer.c_str)); \\ Error on this line
i++;
item_count_++;
}
}
else {
cout << "Error: Failed to open input file." << endl;
}
fin.close();
}
cstr() is a function, so make sure you call it to get the result (rather than treating as a member variable)
p_item_list_[i] = new Product(false, name_buffer, atoi(quantity_buffer.c_str()), atof(price_buffer.c_str()));
Use empty parentheses to call a member function with no parameters:
... atoi(quantity_buffer.c_str()) ...
If the compiler sees c_str without parentheses, it makes a very unreasonable assumption that you want to refer to the function itself, using a pointer to it. This is a rarely-used feature.
To complicate the matters even more, there are two possible syntaxes for pointer to member function, and one of them is non-standard. This is what the compiler complains about. You don't need any of this, so add parentheses to tell the compiler that you want to call the function and not take a pointer to it.
The pair () is the function call operator. Without it you only get the function pointer, no calls are made
But don't use atoi(). See the reason why it should be avoided. Use stoi() instead, and use stod() to get a double
p_item_list_[i] = new Product(false, name_buffer,
stoi(quantity_buffer), stod(price_buffer));
As you can see, the code is much cleaner because there's no .c_str() everywhere, as the sto* family receives std::string directly (which is much better than receiving a const char*)
Another note: don't use such a long lines. No one likes horizontal scrolling
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.
I'm working on creating a program that will take a fraction and reduce it to it's lowest terms. I'm using a tokenizer to parse through the string (In my case I'm reading in a string) and separate the numerator from the denominator.
I'm getting the following error, and am looking for an explanation to why it's happening. I've looked up people with similar problems, but I'm still a beginner looking for a basic explanation and suggestion for an alternative way to solve it.
RationalNum() // Default
:numerator(0), denominator(1){}
RationalNum(int num) // Whole Number
:numerator(num), denominator(1){}
RationalNum(int num, int denom) // Fractional Number
:numerator(num), denominator(denom){}
RationalNum(string s)
{
int num = 0;
char str[] = s;
}
I know the problem lies in the setting the char array to s.
Thanks for taking the time to look at this.
You are trying to initialise an array of char to a std::string, which is an object. The literal meaning of the error is that the compiler is expecting an initialisation that looks something like this :
char str[] = {'1','2','3','4'};
However, since you are planning on string manipulation anyway, you would have a much easier time just keeping the string object rather than trying to assign it to a char array.
Instead of building your parser from scratch, you can use string stream and getline. with '/' as your delimiter. You can initialise an std::stringstream with a string by passing it as an argument when constructing it. You can also use another stringstream to convert a string into a number by using the >> operator.
I have function definition lke below
void ConvertString(std::string &str)
{
size_t pos = 0;
while ((pos = str.find("&", pos)) != std::string::npos) {
str.replace(pos, 1, "and");
pos += 3;
}
}
Purpose of this function is to find & and replace it with and. function execution in fine. I written this for all generalised string at one instance I am calling this in following way
char mystr[80] = "ThisIsSample&String";
ConvertString((std::string)mystr);
printf(mystr);
In above call I am expecting console should be printed with new modified string with "and".
But some of string modification is not working , any error in function?
This code:
char mystr[80] = "ThisIsSample&String";
ConvertString((std::string)mystr);
printf(mystr);
… creates a temporary string object and passes that as argument.
Since the formal argument type is by reference to non-const, this should not compile, but Visual C++ supports it as a language extension (for class types only, IIRC).
Instead do like
string s = "Blah & blah";
ConvertString( s );
cout << s << endl;
By the way, C style casts are in general an invitation to bugs, because the basic nature of such a cast can change very silently from e.g. const_cast to reinterpret_cast when the code is maintained.
It's safe enough in the hands of an experienced programmer, like a power tool such as a chain saw can be safe in the hands of an experienced woodsman, but it's not a thing that a novice should use just to save a little work.
It's because you create a temporary std::string object (whose initial content is the content of the array mystr), and pass that temporary object by reference to the function. This temporary object is then destructed when the call id done.
Did you read some documentation of std::string and of printf?
You need
std::string mystr = "ThisIsSample&String";
ConvertString(mystr);
printf(mystr.c_str());
You obviously want to pass by reference a string variable (technically an l-value) to your ConvertString
I believe your problem is that you cast char array to string.
ConvertString((std::string)mystr);
this line creates a new variable of type std::string and passes it by reference. What you want is to convert it this way:
std::string convertedStr = (std::string)mystr;
ConvertString(convertedStr);
printf(convertedStr.c_str());
I am not very well aware of C++ pointer and reference syntax, but it's similar to this
what your are doing is not correct! you cannot should not convert a char* to a std::string with a cstyle-cast. what you should do is more like:
std::string mystr( "ThisIsSample&String" );
ConvertString(mystr);
edit:
thx for -reputation... this code isn't even compiling...
http://ideone.com/bCsmgf
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.