Reputation: 24771
These work:
struct WithString {
WithString(std::string){};
};
void takeString(std::string){}
//implicit conversions:
takeString("hello");
WithString("hello");
But this does not:
WithString makeWithString() { return "hello";}
// error: no viable conversion from returned value of type 'const char [6]'...
If "hello" is implicitly converted to std::string
in the first two cases, why cannot it not be in the last case? Note that I did not specify the WithString
constructor as explicit
, so I'd expect such a conversion.
I can get the behavior to work by doing this:
struct WithString {
WithString(std::string){};
WithString(const char *){};
};
I'm just curious about this oddity. If I postulate a guess, I would say it is because in the first two working cases, the conversion is between const char *
to std::string
, but in the error case, this would instead require a chain of 2 conversion, first from const char *
to std::string
, and then from std::string
to WithString
. So perhaps that is the reason, but I'm not sure.
Upvotes: 4
Views: 1628
Reputation: 131986
Your method:
WithString makeWithString() { return "hello";}
needs two conversions: The implicit const char *
-to-std::string
conversion, then a construction of a WithString
object. C++ allows at most one of these to happen implicitly. See also the discussion here:
Non-const copy constructor and implicit conversions on return value
Upvotes: 3
Reputation: 31
Read implicit conversions section in the C++ standard. I tried the following code in VS 2015 and it compiled with no errors.
#include <string>
struct WithString {
WithString(std::string) {};
};
void takeString(std::string) {}
//implicit conversions:
void someFunc()
{
takeString("hello");
WithString("hello");
WithString t = "hello";
}
WithString makeWithString() { return "hello"; }
It appears that VS2015 is incorrect (treating a conversion from const char* to string as a standard conversion). The following code should work according to the standard, but produces an error in VS2015:
WithString makeWithString() { return "hello"s; }
WithString t = "hello"s;
See also copy initialization. In the Notes it explicitly calls WithString t = "hello";
an error.
Upvotes: -1
Reputation: 385284
I would say it is because in the first two working cases, the conversion is between const char * to std::string, but in the error case, this would instead require a chain of 2 conversion, first from const char * to std::string, and then from std::string to WithString. So perhaps that is the reason, but I'm not sure.
Exactly.
Without your const char*
constructor overload, this:
WithString makeWithString() { return "hello";}
would require two user-defined implicit conversions; one to std::string
and another to WithString
. That is not possible.
Here, though, there's only one implicit conversion (to std::string
):
takeString("hello");
And the same is true here, because the subsequent "conversion" to WithString
is explicit:
WithString("hello");
I can get the behavior to work by doing this:
struct WithString { WithString(std::string){}; WithString(const char *){}; };
Yes, that's what you should do.
Upvotes: 6