C++ Literal string and const string reference argument [duplicate] - c++

This question already has answers here:
String literal matches bool overload instead of std::string
(4 answers)
Closed 7 years ago.
I have two overload function with const std::string& and bool respectively. I am now calling the function with literal string. The bool version is called. This is a bit weird, and it is really a pitfall.
Can anyone explain why?
See the code below. The output is
Write == 1
#include <iostream>
#include <string>
void write(const std::string& name_) {
std::cout << "Write == " << name_ << std::endl;
}
void write(bool name_) {
std::cout << "Write == " << name_ << std::endl;
}
int main()
{
write("data");
}

The issue is that your argument to write is not a value of type std::string (it is not a literal of std::string) but a character array.
Unfortunately, and I agree with you that it is a pitfall, the rules of the overload resolution will pick the conversion of array to boolean over conversion to const reference to string.
Mind you, there are in C++ 11 actual std::string literals, I won't go into the details here.
What fixes the overload is to convert explicitly to std::string:
write(std::string("data")) will do the right thing.
Prevent this issue in the future. It is indeed a pitfall.

Related

Please explain char* return type in C++ [duplicate]

This question already has answers here:
cout << with char* argument prints string, not pointer value
(6 answers)
Closed 2 years ago.
I have written a simple C++ code, and its working fine. But I don't know how it is working. I am just replacing "l" with "r" using myfun().
The return type of myfun() is char*. If I am returning &(str[0]), that is, only the address of the first element of the array, then why is it printing the complete string "herloworld"? Please explain what return &(str[0]); is doing.
#include <iostream>
using namespace std;
char* myfun(char str[])
{
str[2] = 'r';
return &(str[0]);
}
int main()
{
char str[] = "helloworld";
char* word;
word = myfun(str);
cout << word;
}
The operator << is overloaded for the type char * such a way that it expects that the used pointer of the type char * points to the first character of a string.
So the operator outputs all characters of the passed string until the zero character '\0' is encountered.
Also pay attention to that arrays used in expressions with rare exceptions are converted to pointers to their first elements.
So this call
word = myfun(str);
is equivalent to
word = myfun( &str[0]);
On the other hand, a function parameter having an array type is implicitly adjusted to pointer to the element type.
So this function declaration
char* myfun(char str[]);
is equivalent to the following declaration
char* myfun(char *str);
The both declarations declare the same one function.
And within the function instead of this return statement
return &(str[0]);
you could write
return str;
Correspondingly in main you could write
cout << myfun(str);
without declaring and using the intermediate pointer word.

How would you concatenate "on the fly" a text+integer passing it to a function? [duplicate]

This question already has answers here:
How to concatenate a std::string and an int
(25 answers)
Closed 4 years ago.
I've a function in a library (so, that I cannot change) like this:
char mName[MAX_PARAM_NAME_LEN];
void IParam::InitBool(const char* name) {
strcpy(mName, name);
}
I'd like to pass text as Text0, Text1 (and so on) "faster", writing directly inside the function, starting from a text and an integer, without store additional variables on my own; such as:
int mIndex = 0;
InitBool("Text" + mIndex);
How would you do it? Wrap functions? Which one? Best approch? In C# thats pretty done, I find hard to do it in C++.
If your compiler supports C++17 features you could use a fold expression and string stream. The magic happens in the stringify() function which accepts zero or more arguments.
#include <iostream>
#include <sstream>
#include <string>
template <typename... Ts>
std::string stringify(const Ts&... args)
{
std::ostringstream oss;
(oss << ... << args);
return oss.str();
}
void InitBool(const char *name)
{
std::cout << name << '\n';
}
int main()
{
int mIndex = 0;
InitBool(stringify("Text", mIndex, '!', 1.0/3.0).c_str());
}
Live Demo
In C++ "Text" is a const char[N], it's not actually a string type but just an array of characters with a null character ('\0') at the end. This doesn't support any sort of string manipulation. What you need to get is a std::string, which does support many string operations. Since you need to convert mIndex to a string to begin with we can just to that and the string that represents the number will handle concatenating "Text" to it. That gives you
int mIndex = 0;
InitBool(("Text" + std::to_string(mIndex)).c_str());
The ("Text" + std::to_string(mIndex)) part gives you a temporary std::string that is "Text0" and then the .c_str() gets a const char* to that string to pass to the function.
You can wrap the ("Text" + std::to_string(mIndex)) part in a function like
std::string concat(const char* str, int val)
{
return str + std::to_string(val);
}
and then the function call would look like
InitBool(concat("Text", mIndex).c_str());

Automatically Concatenate Strings and Int C++

In Lua (apologise, I like working with it the best), the conversion between int and string is done automatically, so
"hi"..2
would result as
"hi2"
In C++ (cause I can't seem to get the default C++11 stoi() and to_string() methods to work) I defined these for myself:
int stoi(string str) {
char* ptr;
strtol(str.c_str(), &ptr, 10);
}
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
which are basically how the default ones are defined anyways.
Then I did this:
string operator+ (string& stuff, int why) {
stuff.append(to_string(why));
}
I tried it on the following code:
void print(string str) {
cout << str << endl;
}
int main() {
cout << stoi("1") + 2 << endl;
print("die" + 1);
return 0;
}
And it outputs
3
ie
Why is this so, and how can I fix it?
EDIT:
Here's what the code looks like now:
using namespace std;
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
string operator+ (string stuff, int why) {
stuff.append(to_string(why));
return stuff;
}
int main() {
cout << string("die") + 2 << endl;
return 0;
}
And it just keeps giving me stackdumps.
Replace print("die" + 1); with cout << std::string("die") + 1;
print() doesn't know what to do with strings. Use std::cout. "die" is a char*, +1 will increment the pointer.
std::string to_string(int i) {
char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
sprintf(buf, "%d", i);
return buf;
}
You need to make an actual buffer to print to. The math is a quick over-estimate of big the largest decimal int is in characters; 3 bits can fit in 1 decimal character, plus null, plus negation, plus rounding, plus 1 for good measure. Hopefully I did not err: do some testing.
Also use snprintf instead of sprintf while you are at it: buffer overflows are not to be toyed with.
The next problem is that "hello" is not a std::string, It is a char const[6] -- an array of 6 char. It can be converted tomstd::string, but +1 will instead convert it to a pointer to the first character, then +1 it to the 2nd character.
Cast it to std::string before.
Finally, it is ambiguous in the standard (really) of pverloading an operator on std::string + int is legal. It is definitely poor practice, as you cannot do it in std legally, and you should overload operators in the type's namespace (so ADL works): these two conflict. On top of that, if std in the future adds such a + your code starts behaving strangely. On top of that, operators are part of a class's interface, and modifying the interface of a class you do not 'own' is rude and a bad habit.
Write your own string class that owns a std::string rather. Or a string view.
Finally, consider telling your compiler to use c++11, you probably just need to pass a flag to it like -std=c++11.
std::string s1("h1");
std::string s2("2");
s1 += s2;
If you are using C++11 compatible compiler you can convert int to string like this:
int i = 2;
std::string s = std::to_string(i);
If you are using Boost library:
#include <boost/lexical_cast.hpp>
int i = 2;
std::string s = boost::lexical_cast<std::string>(i);
Please do not use raw char pointers in C++ for strings.
overloading the operator+ on other than your own types it at best dangerous.
Just use std::to_string in conjunction with operator+ or +=, e.g.
std::string x = "hi";
x += std::to_string(2);
C++14 introduces a user-defined literal that takes a string literal (conversions are applied to make this a pointer) and returns a std::string. In C++11, you can just write your own (this is taken from libstdc++):
inline std::string
operator""_s(const char* str, size_t len)
{
return std::string{str, len};
}
(Note: UDLs without a preceding underscore are reserved names)
And you can use it like this:
// Assumes operator+ is overloaded
print("die"_s + 1);
Demo
"die" is not a std::string. It's a string literal.
Thus when you add 1 to the string literal, it decays to a const char* and the + 1 simply increments that pointer — to next char, 'i'.
Then you call print with the incremented pointer, which causes a std::string to be constructed using that pointer. Since it pointed to the 'i' character, to constructed string is initialized to "ie".
You must first make a std::string out of your string literal to make it call your operator+:
std::cout << std::string("die") + 1;
And then make a few fixes to your operator+:
string operator+ (string stuff, int why) {
return stuff.append(to_string(why));
}
Now it works.

C++: Why is 'operator+=' defined but not 'operator+' for strings? [duplicate]

This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 8 years ago.
How come operator+= is defined for std::string but operator+ is not defined? See my MWE below (http://ideone.com/OWQsJk).
#include <iostream>
#include <string>
using namespace std;
int main() {
string first;
first = "Day";
first += "number";
cout << "\nfirst = " << first << endl;
string second;
//second = "abc" + "def"; // This won't compile
cout << "\nsecond = " << second << endl;
return 0;
}
You need to convert one of the raw string literals to std::string explicitly. You can do it like others already mentioned:
second = std::string("abc") + "def";
or with C++14, you will be able to use
using namespace std::literals;
second = "abc"s + "def";
// note ^
Those aren't std::strings, they are const char *. Try this:
second = std::string("abc") + "def";
C++: Why is 'operator+=' defined but not 'operator+' for strings?
It is. It requires at least one of the operands to be an std::string:
int main()
{
std::string foo("foo");
std::string bar("bar");
std::string foobar = foo + bar;
std::cout << foobar << std::endl;
}
The problem in your case is that you are trying to add string literals "abc" and "def". These have type const char[4]. There is no operator+ for these types.
+ will work to concatenate two strings only when at least one operand is of type std::string.
In "abc" + "def", None of the operand is of type std::string.

Is it safe to overload char* and std::string?

I have just read about the overloading functions on a beginner book.
Just out of curiosity I 'd like to ask whether it is safe to overload between char* and std::string.
I played with the below code and get some result. But I was not sure whether it is an undefined behavior.
void foo(std::string str) {
cout << "This is the std::string version. " << endl;
}
void foo(char* str) {
cout << "This is the char* version. " << endl;
}
int main(int argc, char *argv[]) {
foo("Hello"); // result shows char* version is invoked
std::string s = "Hello";
foo(s); // result shows std::string version
return 0;
}
Yes, it's safe, as long as you make it const char*, and actually often useful. String literals cannot be converted to char* since C++11 (and it was deprecated before that).
The const char* overload will be picked for a string literal because a string literal is a const char[N] (where N is the number of characters). Overloads have a kind of priority ordering over which one will be picked when multiple would work. It's considered a better match to perform array-to-pointer conversion than to construct a std::string.
Why can overloading std::string and const char* be useful? If you had, for example, one overload for std::string and one for an bool, the bool would get called when you passed a string literal. That's because the bool overload is still considered a better match than constructing a std::string. We can get around this by providing a const char* overload, which will beat the bool overload, and can just forward to the std::string overload.
Short Answer: Perfectly safe. Consider the following uses:
foo("bar");//uses c string
foo(std::string("bar") );//uses std::string
char* bar = "bar";
foo(bar);//uses c string
std::string bar_string = "bar";
foo(bar_string);//uses std::string
foo(bar_string.c_str()); //uses c string
Word of warning, some compilers (namely those with c++11 enabled) require the const keyword in parameter specification in order to allow temporary strings to be used.
For instance, in order to get this:
foo("bar");
You need this:
void foo(const char* bar);