Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can compiler only implicitly convert char * to std::string in some cases

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.

like image 991
johnbakers Avatar asked Feb 06 '23 08:02

johnbakers


2 Answers

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.

like image 123
Lightness Races in Orbit Avatar answered Feb 08 '23 17:02

Lightness Races in Orbit


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

like image 26
einpoklum Avatar answered Feb 08 '23 15:02

einpoklum