Почему в некоторых случаях компилятор может неявно преобразовывать char * в std::string

Эти работы:

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]'...

Если "привет" неявно преобразуется в std::string в первых двух случаях почему бы не быть в последнем случае? Обратите внимание, что я не указал WithString конструктор как explicit, так что я ожидаю такого преобразования.

Я могу заставить поведение работать следующим образом:

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

Мне просто любопытно об этой странности. Если я постулирую предположение, я бы сказал, что это потому, что в первых двух рабочих случаях преобразование происходит между const char * в std::string, но в случае ошибки вместо этого потребуется преобразование цепочки из 2, сначала из const char * в std::stringа затем из std::string в WithString, Так что, возможно, в этом причина, но я не уверен.

3 ответа

Решение

Ваш метод:

WithString makeWithString() { return "hello";}

требуется два преобразования: неявное преобразование const-char-*-to-std::string, затем конструкция WithString объект. C++ позволяет не более чем одному из них происходить неявно. Смотрите также обсуждение здесь:

Неконстантный конструктор копирования и неявные преобразования возвращаемого значения

Я бы сказал, что это потому, что в первых двух рабочих случаях преобразование происходит между const char * в std:: string, но в случае ошибки вместо этого потребуется преобразование цепочки из 2, сначала из const char * в std:: строка, а затем из std:: string в WithString. Так что, возможно, в этом причина, но я не уверен.

Именно так.

Без вашего const char* перегрузка конструктора, это:

WithString makeWithString() { return "hello";}

потребует двух пользовательских неявных преобразований; один к std::string и другой, чтобы WithString, Это невозможно.

Здесь, однако, есть только одно неявное преобразование (в std::string):

takeString("hello");

И то же самое здесь, потому что последующее "преобразование" в WithString явно:

WithString("hello");

Я могу заставить поведение работать следующим образом:

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

Да, это то, что вы должны сделать.

Читайте раздел неявных преобразований в стандарте C++. Я попробовал следующий код в 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* в string как стандартное преобразование). Следующий код должен работать в соответствии со стандартом, но выдает ошибку в VS2015:

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

Смотрите также копию инициализации. В примечаниях это явно вызывает WithString t = "hello"; ошибка.

Другие вопросы по тегам