Erel Segal-Halevi
Erel Segal-Halevi

Reputation: 36715

How can I have both conversion constructor and conversion operator?

Consider this simple C++-17 program:

#include <iostream>
#include <math.h>
using namespace std;


class Fraction {
public:
    int     nom;
    int     den;
    Fraction operator+ (const Fraction& other) {
        int nn = nom * other.den +
            den * other.nom;
        int dd = den * other.den;
        return Fraction(nn, dd);
    }
    Fraction(int nn, int dn): nom(nn), den(dn) { }
    Fraction(int nn): nom(nn), den(1) { }
    operator double() const { return double(nom) / den; }
};

ostream& operator<<(ostream& os, const Fraction& frac) {
    return os << frac.nom << '/' << frac.den;
}


int main() {
    Fraction f1(1, 4);
    cout << "f1 = " << f1 << endl << "f1+2 = " << (f1 + 2) << endl;
    return 0;
}

This program yields a compilation error:

main.cpp:35:52: error: use of overloaded operator '+' is ambiguous (with operand types 'Fraction' and 'int')
        cout << "f1 = " << f1 << endl << "f1+2 = " << (f1 + 2) << endl;
                                                       ~~ ^ ~
main.cpp:17:11: note: candidate function
        Fraction operator+ (const Fraction& other) {
                 ^
main.cpp:35:52: note: built-in candidate operator+(double, int)
        cout << "f1 = " << f1 << endl << "f1+2 = " << (f1 + 2) << endl;
                                                          ^

However, if I remove either the conversion constructor "Fraction(int nn): nom(nn), den(1) { }" or the conversion operator "operator double() const { return double(nom) / den; }", the program runs fine.

I want to convert both to and from Fraction. What can I do to have both conversions and still have the program compile?

Upvotes: 0

Views: 276

Answers (2)

Chintan
Chintan

Reputation: 372

From the error, the compiler is complaining as it can't resolve the ambiguity on its own. As it correctly points out there are 2 possible solutions and it doesn't know which one to pick without additional insight from you.

How would you like (f1 + 2) evaluated, if you want Fraction addition, recommend changing caller to (f1 + Fraction(2)).

If you instead want double addition, change it to (double(f1)+2).

Bottom line, you can continue to have both conversion from fraction to double & integer to fraction construction, but you will need to explicitly specify the behavior you want when there is ambiguity for the compiler.

Upvotes: 2

Make one or both conversion functions explicit. That will prevent your friendly compiler from implicitly using them when choosing an overload of operator + based on implicit conversions sequences.

explicit Fraction(int nn): nom(nn), den(1) { }
explicit operator double() const { return double(nom) / den; }

Just bear in mind it prevents all uses of those functions for implicit conversions.

Upvotes: 2

Related Questions