1

from the answer, I learned std::string is just typedef of std::basic_string<char, std::char_traits<char>, std::allocator<char>>, Template argument substitution does not consider user-defined conversions, so the compiler can't deduce the types CharT, Traits, or Allocator from the type Rectangle, so this overload does not participate in overload resolution.

Now I substitute std::basic_string, std::allocator> for std::string:

class Rectangle
{
public:
    Rectangle(double x, double y) : _x(x), _y(y) {}
    operator std::basic_string<char, std::char_traits<char>, std::allocator<char>> () {
        return std::basic_string<char, std::char_traits<char>, std::allocator<char>>(to_string(_x) + " " + to_string(_y));
    }
    //operator double() {
    //  return _x;
    //}
private:
    double _x, _y;
    double getArea() { return _x * _y; }
};

int main()
{
    Rectangle r(3, 2.5);
    cout << r << endl;
    return 0;
}

It still fails. Why?

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);
Chen Li
  • 4,824
  • 3
  • 28
  • 55
  • you can define `std::ostream& operator<< (std::ostream& stream, const Rectangle& rectangle)` or use `cout << (string)r` – apple apple Nov 09 '17 at 11:51

2 Answers2

3

Now I substitute std::basic_string, std::allocator> for std::string:
It still fails. Why?

You misunderstood the original problem. It wasn't because you used std::string instead of the direct std::basic_string<char, std::char_traits<char>, std::allocator<char>>. A typedef is just another name for an existing type. Your two conversion operators are exactly the same. You can verify that by trying to place them both in the class definition, it will cause a redefinition error.

Both aren't taken into account when resolving the overloads for operator<<, because conversions aren't applied to template function ordering.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
2

Overload resolution first finds a set of possible functions to call. In this phase template deduction is performed to see if a template is a possible candidate.

Then, if more than one function is found, conversion functions are considered when trying to find the closest match among the candidates.

In your case, the operator taking a std::string is never considered as the compiler cannot deduce CharTetc from Rectangle.


A solution is to skip the conversion operator and instead add an operator<< for Rectangle. Inside that you can just call os << to_string(... etc.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203