How does C++ compiler find closest type conversion when displaying my class object?

Viewed 76

I write a class Fraction, and would like to display Fraction object with std::cout:

Fraction f(3, 5);
std::cout << f << std::endl;

I know overloading operator << can be used for this display purpose. But I can also overload operator type() function, and when only with operator double()(let type be double), I can still std::cout << f << std::endl.

Even more, I can also implement operator std::string(). But, when the mentioned 3 overloaded operator functions all exist, without explicitly type conversion, which one is called when doing std::cout << f << std::endl ? This really makes me curious, is this undefined behavior denpending on compiler implementation, or if there is some rule for scoring the closest/most suitable function to call?

To reproduce, use the following code:

#include <iostream>
#include <string>

class Fraction
{
public:
    Fraction(int num, int den=1):
        numerator(num), denominator(den) {}
    
    operator double() const {
        std::cout << "[operator double()]";
        return numerator*1.0 / denominator;
    }

    operator std::string() const {
        std::cout << "[operator std::string()]";
        return std::to_string(numerator) + "/" + std::to_string(denominator);
    }

private:
    int numerator;
    int denominator;

#ifdef OVERLOAD_STREAM_OP
    friend std::ostream& operator << (std::ostream& os, const Fraction& frac);
#endif

};

#ifdef OVERLOAD_STREAM_OP
std::ostream& operator << (std::ostream& os, const Fraction& frac)
{
    std::cout << "[operator <<]";
    os << std::to_string(frac.numerator) << "/" << std::to_string(frac.denominator);
    return os;
}
#endif

int main()
{
    Fraction f(3, 5);
    double d = 4 + f;
    std::cout << "\n--- now let's print\n";
    std::cout << "f: " << f << std::endl;
    std::cout << "f: " << std::string(f) << std::endl;
    std::cout << d << std::endl;

    return 0;
}

The output on my ubuntu 20.04:

(base) zz@home% clang++ fraction.cpp
(base) zz@home% ./a.out 
[operator double()]
--- now let's print
f: [operator double()]0.6
f: [operator std::string()]3/5
4.6
0 Answers
Related