Подтвердить что ты не робот

С++ перегружает оператор преобразования для настраиваемого типа на std::string

Я надеюсь, что кто-то сможет ответить, почему следующее не работает. Потерпите меня, хотя я все еще очень люблю... Я просто не могу понять, почему следующие

using namespace std;
#include <string>
#include <iostream>

class testClass
{
public:
 operator char* () {return (char*)"hi";};
 operator int ()  {return 77;};
 operator std::string  () {return "hello";};
};

int main()
{
 char* c;
 int i;
 std::string s = "goodday";

 testClass t;

 c = t;
 i = t;
 s = t;

 cout<< "char: " << c << " int: " << i << " string: "<<s<<endl;

 return 0;
}

дает мне ошибку времени компиляции:

myMain.cpp: In function ‘int main()’:
myMain.cpp:23: error: ambiguous overload for ‘operator=’ in ‘s = t’
/usr/include/c++/4.2.1/bits/basic_string.h:500: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.h:508: note:                 std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.h:519: note:                 std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]

Если я не пытаюсь выполнить назначение

s = t;

он работает.

Я пытался часами даже понять сообщение об ошибке, но меня больше всего озадачило то, что работает на char *.

Я благодарен за любой намек. Благодарю! Маркус

4b9b3361

Ответ 1

То, что ошибка пытается объяснить, заключается в том, что ваше назначение "s = t", где s является std::string, было бы правильным, если бы t были std::string тоже, или если t были a [const] char*. Ваши операторы преобразования могут преобразовать t в любой из них, поэтому у компилятора нет оснований для выбора одного из них.

Вы можете явно устранить эту проблему, выбрав желаемое преобразование:

s = t.operator std::string();
s = static_cast<std::string>(t);

Или вы можете предоставить только одно из преобразований и позволить пользователю делать дальнейшее преобразование, когда это необходимо.

В конце концов вы можете найти, что любой оператор преобразования больше проблем, чем он того стоит... он говорит, что std::string сам не предоставляет оператор преобразования для const char*.

Ответ 2

$13.3.1.5/2 заявляет: "Преобразование функции S и его базовые классы которые считаются. Те, которые не являются спрятаны внутри S и выдают тип T или тип, который можно преобразовать в тип T через стандартную последовательность преобразования (13.3.3.1.1) являются кандидатскими функциями. Функции преобразования, которые возвращают cv-квалифицированный тип дают неквалифицированную версию cv этот тип для этого процесса выбор кандидатских функций. Возвращаемые функции преобразования" Ссылка на cv2 X "возвращает lvalues типа" cv2 X" и, следовательно, считается, что для этого процесса X выбора функций-кандидатов.

Назначение s = t работает следующим образом:

a) Рассматриваются все члены типа 't' (testClass), которые могут преобразовывать 't' в 's'.

Candidate 1: operator string();   // s created using member string::operator=(string const&)
Candidate 2: operator char *()    // s created using member string::operator=(char const*)
Candidate 3: operator char *()    // s created using member string::operator=(char *)

b) Все вышеперечисленные кандидаты жизнеспособны (т.е. в отсутствие других кандидатов компилятор может успешно разрешить вызов функции любому из них)

c) Однако теперь нужно определить наилучшего жизнеспособного кандидата. Применяемые последовательности преобразования:

Candidate 1: U1 : operator string()
Candidate 2: U2 : operator char*()->const qualification to match string::operator=(char const*)
Candidate 3: U3 : operator char*()

$13.3.3.1.1/3 состояния - "Ранг a последовательность преобразований определяется учитывая ранг каждого преобразования в последовательности и ранг любого ссылочного связывания (13.3.3.1.4). Если кто-либо из них Ранг преобразования, последовательность имеет Ранг конверсии;

Это означает, что U1, U2 и U3 все имеют ранг конверсии, а на первом уровне ни один не лучше другого. Однако в стандарте также указано

Пользовательская последовательность преобразования U1 является лучшая последовательность преобразования, чем другое пользовательское преобразование последовательность U2, если они содержат одинаковые пользовательская функция преобразования или конструктор, и если второй стандарт последовательность преобразования U1 лучше чем второе стандартное преобразование последовательность U2.

Итак, посмотрим, что это значит.

Между U1 и U2 они включают в себя различные функции преобразования и, следовательно, ни один не лучше других

Между U1 и U3 они включают в себя различные функции преобразования и, следовательно, ни один не лучше другого

А как насчет U1 и U2. Они включают одну и ту же функцию преобразования, которая удовлетворяет первой части "и" условия выше

Итак, как насчет части ", и если вторая стандартная последовательность преобразования U1 лучше второй стандартной последовательности преобразования U2."

В U2 вторая стандартная последовательность преобразований требует квалификации const, где в U3 это не требуется. Вторая стандартная последовательность преобразования U3 - это точное соответствие.

Но, как и в Таблице 9 в Стандартных состояниях, квалификация CV также считается Точным соответствием.

Следовательно, U2 и U3 также действительно неразличимы в отношении разрешения перегрузки.

Это означает, что U1, U2 и U3 все так же хороши, как и другие, и компилятор считает, что вызов (как часть инструкции присваивания) является неоднозначным, поскольку нет однозначной лучшей жизнеспособной функции

Ответ 3

Нет точного std::string:: operator =. Кандидаты перефразированы,

s = (const std::string)(std::string)t;
s = (const char*)t;
s = (char)(int)t;

Я думаю, что все будет работать, если вы измените его на return const std::string. ( EDIT: Я ошибаюсь.) Также обратите внимание, что первая функция должна вернуться const char *. Если вам нужно передать строковый литерал в char *, вы делаете что-то неправильно; Строковые литералы не могут быть записаны.

Ответ 4

На самом деле это потому, что std::string предлагает оператор присваивания, который принимает const char*.

Ответ 5

Хорошо, спасибо много уже всем. Я думаю, что я начинаю навязывать это, вроде...

Прежде всего, я не знал о том, что char - это всего лишь 8-битный int. Спасибо за это разъяснение.

Итак, я понимаю, потому что для std::string определены три оператора присваивания, каждый из которых имеет разные аргументы (строка, char *, const char *) правая часть моего выражения

s=t

не знает, к какому типу нужно преобразовать, поскольку существует несколько, потенциально подходящих (для этого назначения для std::string) конверсий, определенных с помощью

operator int ()  {return 77;};
operator std::string  () {return "hello";};

(так как char: 8bit int)

или

operator char* () {return (char*)"hi";};
operator std::string  () {return "hello";};

Это правильно? Итак, в терминах идиотов левая сторона задания не говорит правой стороне, какой тип он ожидает, поэтому rhs должен выбирать из своих опций, где один так же хорош, как какой-то другой? std::string operator = толерантен к моим намерениям?

До сих пор так хорошо, я думал, что понял, но потом, почему следующие создают двусмысленность?

 using namespace std;
 #include <string>
 #include <iostream>

 class testClass
  {
   public:
     operator float ()  {return float(77.333);};
     operator std::string  () {return "hello";};
  };

  int main()
  {
    std::string s = "goodday";
    testClass t;

    s = t;

    cout<< " string: "<<s <<endl;

    return 0;
  }

Теперь есть только один оператор преобразования, определенный мной, не так ли? std::string operator = не может принимать поплавки или может? Или снова поплавком эквивалентен некоторому варианту char?

Я понимаю код как 's =', указывающий rhs: "дайте мне строку, char * или const char *"

Rhs проверяет, что он может предоставить, учитывая экземпляр testClass, и единственным совпадением является testClass:: operator std::string

Снова, спасибо за ваше терпение, опыт и время, ребята, я очень ценю это.