Нечеткое использование оператора double()
У меня есть класс Rectangle
с операторами преобразования в double
и std::string
:
class Rectangle
{
public:
Rectangle(double x, double y) : _x(x), _y(y) {}
operator std::string ();
operator double ();
private:
double _x, _y;
double getArea() {return _x * _y;}
};
int main()
{
Rectangle r(3, 2.5);
cout << r << endl;
return 0;
}
Я не понимаю, почему вызывается operator double()
, а не operator std::string()
. Насколько я знаю, согласно C++ wikibook, operator double
используется для преобразования объектов Rectangle
в double
.
Так что здесь происходит? Связано ли это с тем, что int
передается конструктору? Если так, то почему?
Ответы
Ответ 1
У вас нет оператора для вывода прямоугольника в поток. cout
имеет перегрузку, которая принимает double
и ваш класс может быть неявно преобразован в double
так что это выбирается.
Причина, по которой перегрузка строки не выбрана и не рассматривается как неоднозначность, заключается в том, что operator <<
для строки является функцией-членом и не включен в набор перегрузки членов и не членов перегрузки cout
. Если мы закомментируем operator double
мы увидим ошибку компилятора.
Если мы хотим вызвать operator string
нам нужно явно привести r
в строку. Live Example
Ответ 2
Поскольку вы не указали перегрузку operator<<
для Rectangle
, компилятор рассматривает другие перегрузки, для которых аргументы могут быть преобразованы в типы параметров.
Если какая-либо из перегрузок является шаблонами, то замена шаблона аргумента происходит с ними до разрешения перегрузки. Компилятор пытается вывести параметры шаблона из типов аргументов, предоставленных функции.
Перегрузка string
не рассматривается из-за неудачной замены аргумента замены шаблона:
template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str);
Подстановка аргумента шаблона не учитывает пользовательские преобразования, поэтому компилятор не может выводить типы CharT
, Traits
или Allocator
из типа Rectangle
, поэтому эта перегрузка не участвует в перегрузке разрешающая способность. (Напомним, что std::string
- это всего лишь typedef std::basic_string<char, std::char_traits<char>, std::allocator<char>>
.)
Поэтому существует одна перегрузка operator<<
, которая лучше, чем любая другая, и это перегрузка double
. Не шаблон, а член-функция шаблона класса.
basic_ostream<CharT, Traits>& basic_ostream<CharT, Traits>::operator<<(double);
Ответ 3
В двойной перегрузке нет ничего особенного, чем перегрузки других примитивных типов. В этом случае это единственная доступная примитивная перегрузка. Компилятор будет вести себя одинаково для int, char и т.д.
Обратите внимание: если у нас будет несколько перегрузок примитивного типа, компилятор выдаст
error: ambiguous overload for 'operator<<' ...