2010-08-19 2 views
12

Надеюсь, кто-то может ответить, почему следующее не работает. Медведь со мной, хотя я до сих пор очень нуб ... Я просто не могу добраться до сути, почему следующееC++ перегрузка оператора преобразования для настраиваемого типа в 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 *.

Я благодарен за любой намек. Спасибо! Markus

ответ

1

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

+1

Так что означает, что оператор станд :: строка =() и мои TestClass :: Оператор станд :: строка() конкурируют за работу? – Markus

+1

@Markus: поскольку другие были достаточно любезны, чтобы объяснить, оператор присваивания перегружен и может обрабатывать более одного типа, для которого ваш класс имеет неявное преобразование. –

10

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

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

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

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

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

+0

Но он не компилируется, даже если я беру переменную c и оператор char * из уравнения. Я стараюсь избегать явного устранения значения пользователем класса testClass, пытаясь обойти невозможность перегрузить функции-члены, отличающиеся от возвращаемого значения. – Markus

+1

В соответствии с сообщением об ошибке третий оператор присваивания std :: string, связанный с неопределенностью, относится к типу «char» ... к сожалению, ваш тестовый класс имеет неявное преобразование в int, а char - это просто (обычно) 8-разрядный int .... Я сочувствую вашей цели ... было бы здорово, если бы существовало хорошее решение - представьте себе, что не нужно так часто вызывать std :: string :: c_str(), но, к сожалению, доступные подходы имеют проблемы. Возможно, C++ должен поддерживать обозначение, чтобы устранить такие ситуации - когда программист уверен, что все совпадения функционально эквивалентны, но на данный момент ... :-(. –

+0

«Функционально эквивалентный» не означает эквивалент, хотя. Построение/назначение string with const std :: string &, вероятно, будет более эффективным, чем const char * (с GCC libstdC++, он разделяет буфер и, действительно, копирует-на-запись), даже если они в противном случае выглядят одинаково. –

3

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

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

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

+0

Просто попробовал, и он, похоже, не работает. И спасибо за подсказку. Я знаю, что мне нужно подумать и узнать больше о том, когда вещи или должны быть const ... – Markus

+0

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

+0

Очевидно, что мой C++ - Fu не до нуля. Он должен выбрать как оператор трансляции, так и оператор присваивания, и нет никаких причин, чтобы он предпочитал 'operator = (const std :: string &)' to 'operator = (const char *)'. Я не уверен, можете ли вы определить глобальные операторы присваивания (например, ':: operator = (std :: string &, const testClass &)', но если это сработает, это может быть решением.) –

9

$13.3.1.5/2 states- "The conversion functions of S and its base classes are considered. Those that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions. Conversion functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type for this process of selecting candidate functions. Conversion functions that return “reference to cv2 X” return lvalues of type “cv2 X” and are therefore considered to yield X for this process of selecting candidate functions."

= уступка с т работает следующим образом:

а) Все члены в типе 'т' (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 *) 

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

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

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 states - "The rank of a conversion sequence is determined by considering the rank of each conversion in the sequence and the rank of any reference binding (13.3.3.1.4). If any of those has Conversion rank, the sequence has Conversion rank;"

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

User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function or constructor and if the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.

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

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

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

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

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

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

Но как указано в Таблице 9 в штатах, квалификация CV также считается точной совпадением.

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

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

+0

друзей, у меня трудности с форматированием шаг (c) в блочных кавычках. Нужна помощь. – Chubsdad

+0

Вам нужна дополнительная новая строка. – greyfade

+0

@greyfade: Thanks buddy – Chubsdad

0

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

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

Так что я понимаю, что, потому что есть три оператора присваивания, определенный для станда :: строки, каждый с другим аргументом (строкой, символ *, Const символ *) в правой стороне моего выражения

s=t 

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

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

(так как символ: 8bit межд)

или

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 проверяет, что он может обеспечить данный экземпляр TestClass, и единственным матчем is testClass :: operator std :: string

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

+0

Это потому, что «float» можно преобразовать в «char» как часть стандартной последовательности конвертирования с плавающим интегралом. Если вам трудно понять сообщения компилятора, один из способов изучить концепцию - прокомментировать «операторскую строку()» и проверить, что происходит в коде. VS дает «предупреждение C4244:« аргумент »: преобразование из« float »в« char », возможная потеря данных». Это означает, что оператор float() является кандидатом, а совпадение для вызова этого оператора требует преобразования из float в char – Chubsdad

+0

Хорошо, поэтому мне еще предстоит многое узнать. Еще раз спасибо всем! Наверное, мой, то, что я думал как элегантное решение, не работает в конце концов ... – Markus

 Смежные вопросы

  • Нет связанных вопросов^_^