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.
Related
I want to simplify the using of strings like in java.
so i can write "count "+6; and get a string "count 6"
with std::string it's possible to concatenate two strings or std::string with char string.
i wrote 2 functions
template<typename T>
inline static std::string operator+(const std::string str, const T gen){
return str + std::to_string(gen);
}
template<typename T>
inline static std::string operator+(const T gen, const std::string str){
return std::to_string(gen) + str;
}
to concatenate std::string with numbers, but cannot write something like "count "+6; because "count " is a const char[] and not a std::string.
it works with std::string("count")+" is "+6+" and it works also with double "+1.234; , but thats not really pretty =)
is there a possibility to do the same without starting with std::string("")
template<typename T>
inline static std::string operator+(const char* str, const T gen){
return str + std::to_string(gen);
}
this method doesn't work and i get an compiler error
error: invalid operands of types 'const char*' and 'const char [1]' to binary 'operator+'
No. You cannot overload operators for built-in types only; one of the two types involved in the operation must either be a class type or an enumeration.
What you could do to make things more palatable is construct strings on the fly by using a user-defined literal:
"count"s + 3.1415;
Be aware that this is a C++14 feature that may or may not be supported by your compiler yet.
When overloading operators, at least one of the operands has to be a user type (while types from the std library are considered user types). In other words: Not both operands of operator+ can be builtin types.
Since C++11, there are literal operators available. They make it possible to write
"count "_s
instead of
std::string("count ")
Such an operator is defined like this (the name of the following literal operator is _s; they have to start with an underscore for custom literal operator overloads):
std::string operator ""_s(const char *str, std::size_t len) {
return std::string(str, len);
}
Then, your expression becomes
"count "_s + 6
In C++14, such an operator is already available, and named more conveniently s (the standard may use operator names without a leading underscore), so it becomes
"count "s + 6
This question already has an answer here:
Implicit conversion with operator
(1 answer)
Closed 7 years ago.
I recently gave an answer to this question on how to get Python-like string repeats, e.g. "hello" * 2 gives "hellohello".
I won't repeat the definition here, but the function declaration is:
std::string repeat(std::string str, const std::size_t n);
and can of course can be used like:
std::cout << repeat("helloworld", 2) << std::endl;
To get closer to the Python version, I thought I'd overload operator*. Ideally I'd use a universal reference to avoid the additional std::string move, but operators must use a user-defined type. So I tried this instead:
#include <type_traits> // std::enable_if_t, std::is_integral
#include <utility> // std::move
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
std::string operator*(std::string str, const T n)
{
return repeat(std::move(str), static_cast<std::size_t>(n));
}
Now I can do this:
std::cout << (std::string("helloworld") * 2) << std::end;
and this:
std::cout << operator*("helloworld", 2) << std::endl;
but not this:
std::cout << ("helloworld" * 2) << std::endl;
// error: invalid operands to binary expression ('const char *' and 'int')
Why not?
When you define an overloaded operator, at least one of the operands must be of a user-defined type. For pre-defined types, all operators are either pre-defined, or else prohibited.
Where you've explicitly converted to std::string the string ctor that takes a char const * as its parameter can/will be used to convert the literal to an std::string, but without that, the compiler can't/won't do the conversion.
Likewise, when you invoke the operator more explicitly as operator*("helloworld", 2), the compiler "knows" that it needs to convert the string literal to a type supported by an overload of operator *, so it (basically) enumerates all the types to which a string literal can be converted, and then sees if it can find an operator * that fits one of those types. If it finds more than one, it does (if memory serves) normal overload resolution on the candidate operator * implementations to decide which to use.
With just the expression string-literal * int, however, both types are built in, so it only examines the built-in operators. Since none of them fits, the expression is prohibited.
Note that with a current compiler, you could use a suffix of s on the string literal to create a std::string:
#include <string>
std::cout << "helloworld"s * s << "\n";
Because "helloworld" is not a std::string, it's a char array.
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.
EDIT: Following Mike Seymour's comment, I replaced operator std::string () const; with operator char * () const; and changed the implementation accordingly. This allows implicit casting, but, for some reason, the unsigned long int operator has precedence over the char * operator, which just does not feel right... Also, I don't want to expose nasty C stuff like char * outside the class, when I have std::string. I have a hunch that my CustomizedInt class needs to inherit from some stuff in order to support the feature that I desire. Could anybody please elaborate Mike's comment regarding std::basic_string? I'm not sure I understood it properly.
I have this piece of code:
#include <string>
#include <sstream>
#include <iostream>
class CustomizedInt
{
private:
int data;
public:
CustomizedInt() : data(123)
{
}
operator unsigned long int () const;
operator std::string () const;
};
CustomizedInt::operator unsigned long int () const
{
std::cout << "Called operator unsigned long int; ";
unsigned long int output;
output = (unsigned long int)data;
return output;
}
CustomizedInt::operator std::string () const
{
std::cout << "Called operator std::string; ";
std::stringstream ss;
ss << this->data;
return ss.str();
}
int main()
{
CustomizedInt x;
std::cout << x << std::endl;
return 0;
}
Which prints "Called operator unsigned long int; 123". My questions are these:
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence? It seems that if I add an operator unsigned int to this class together with the operator unsigned long int, I receive a compiler error about ambiguity for the << operator...
Also, I know that defining such an operator may be poor practice, but I am not sure I fully understand the associated caveats. Could somebody please outline them? Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
The version of << for strings is a template, parametrised by the parameters of the std::basic_string template (std::string itself being a specialisation of that template). It can only be chosen by argument-dependent lookup, and that only works if the argument is actually a specialisation of std::basic_string, not something convertible to that.
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence?
The rules are quite complex, and you'd need to read the C++ standard for the full story. Simple rules of thumb are that implicit conversions can't contain more than one user-defined conversion and (as you've found out) the result of an implicit conversion can't be used to choose a template specialisation by argument-dependent lookup.
I am not sure I fully understand the associated caveats. Could somebody please outline them?
I don't fully understand them either; the interactions between implicit conversions, name lookup and template specialisation (and probably other factors that I can't think of right now) are rather complex, and most people don't have the inclination to learn them all. There are quite a few instances where implicit conversion won't happen, and others where it might happen when you don't expect it; personally, I find it easier just to avoid implicit conversions most of the time.
Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
That's probably a good idea, to avoid unwanted conversions. You can fix your problem by leaving them and use them explicitly when necessary:
std::cout << std::string(x) << std::endl;
In C++11, you can declare them explicit, so that they can only be used in this manner. In my opinion, that would be the best option if you can; otherwise, I would use explicit conversion functions as you suggest.
By the way, the return type of main() must be int, not void.
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.