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

Нечеткое использование оператора 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 передается конструктору? Если так, то почему?

4b9b3361

Ответ 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<<' ...