С++ перегружает оператор преобразования для настраиваемого типа на 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 *.
Я благодарен за любой намек.
Благодарю!
Маркус
Ответы
Ответ 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
Снова, спасибо за ваше терпение, опыт и время, ребята, я очень ценю это.