为什么编译器在某些情况下只能将 char * 隐式转换为 std::string

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

这些工作:

struct WithString {
  WithString(std::string){};
};

void takeString(std::string){}

//implicit conversions:
takeString("hello");
WithString("hello");

但这不是:

WithString makeWithString() { return "hello";}

// error: no viable conversion from returned value of type 'const char [6]'...

如果前两种情况下"hello"隐式转换为std::string,为什么最后一种情况不能呢?请注意,我没有将 WithString 构造函数指定为 explicit,因此我期望这样的转换。

我可以通过这样做使行为起作用:

struct WithString {
  WithString(std::string){};
  WithString(const char *){};
};

我只是对这个怪事感到好奇。如果我假设一个猜测,我会说这是因为在前两个工作情况下,转换是在 const char *std::string 之间,但在错误情况下,这将需要一系列 2 转换,首先从const char *std::string,然后从std::stringWithString。所以也许这就是原因,但我不确定。

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.

完全正确。

没有你的 const char* 构造函数重载,这个:

WithString makeWithString() { return "hello";}

需要两次 user-defined 隐式转换;一个到 std::string,另一个到 WithString。那是不可能的。

这里只有一个隐式转换(到 std::string):

takeString("hello");

这里也是一样,因为后面的"conversion"到WithString是显式的:

WithString("hello");

I can get the behavior to work by doing this:

struct WithString {
  WithString(std::string){};
  WithString(const char *){};
};

是的,这就是你应该做的。

你的方法:

WithString makeWithString() { return "hello";}

需要两次转换:隐式的 const char *std::string 转换,然后是 WithString 对象的构造。 C++ 最多允许其中之一隐式发生。另请参阅此处的讨论:

Non-const copy constructor and implicit conversions on return value

阅读 C++ 标准中的 implicit conversions 部分。我在 VS 2015 中尝试了以下代码并且编译没有错误。

#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"; }

VS2015 似乎不正确(将 const char* 到字符串的转换视为标准转换)。以下代码应符合标准,但在 VS2015 中会产生错误:

WithString makeWithString() { return "hello"s; }
WithString t = "hello"s;

另见 copy initialization。在注释中它明确调用 WithString t = "hello"; 一个错误。