Search code examples
c++classoperator-overloadingimplicit-conversionoverload-resolution

How to std::cout << a type which has many (ambiguous) user-defined conversion functions?


Here I've got a class in c++ that deals with large numbers way beyond long long. It stores its data as std::string. Now I have many, many converters here:

class BigInt {
private:
    std::string x;
public:
    operator std::string()        { return x;              }
    operator int()                { return std::stoi(x);   }
    operator long long()          { return std::stoll(x);  }
    operator unsigned long long() { return std::stoull(x); }
    operator double()             { return std::stod(x);   }
    operator long double()        { return std::stold(x);  }
    ...
    BigInt(std::string a) : x(a) {}
    BigInt(long long a) : x(to_string(a)) {}
    ...
}
int main() {
    BigInt x = 10485761048576;
    std::cout << x << std::endl; // Error!
}

But what happens is that I get an error:

More than one operator matches these operands.

That basically means that the function std::cout doesn't know which converter to choose. So is there a thing as a "default" converter that choose one of the converters as default when accessing functions?

If there is no that kind of thing, then I guess I would have to call something like std::cout << (std::string)x << std::endl; every single time I want to pass the parameter into some kind of overloaded function.


Solution

  • You can supply an overload of std::ostream operator<< for your BigInt:

    std::ostream& operator<<(std::ostream& os, const BigInt& obj)
    {
        os << static_cast<std::string>(obj);
        return os;
    }
    

    In order to be able to use your conversion operators for const objects (as required for the above operator<<, and it is good practice anyway), you also need to mark them const, e.g.:

    //  -----------------------vvvvv--------------
        operator std::string() const { return x; }
    

    Now you can use:

    int main() 
    {
        BigInt x = 10485761048576;
        std::cout << x << std::endl;
    }
    

    Output:

    10485761048576
    

    Live demo - Godbolt.