4

Consider the following code:

class C {
  public:
    int operator-(int x) {
        return 3-x;
    }
};

class wrapper {
  public:
    operator C() {
        static C z;
        return z;
    }
} wrap;

int main() {
    return wrap-3;
}

it gives this error on g++:

test.cpp: In function ‘int main()’:
test.cpp:17:17: error: no match for ‘operator-’ in ‘wrap - 3’

The conversion operator seems to be working because this version works:

class wrapper {
  public:
    operator int() {
        static int z=3;
        return z--;
    }
} wrap;

int main() {
    return wrap-3;
}

operator- also seems to be working because this code compiles:

class C {
  public:
    int operator-(int x) {
        return 3-x;
    }
};

int main() {
    C c
    return c-3;
}

What's wrong with the combination of these two? Why can't an operator be applied after implicit conversion? Are there any workarounds to this problem?

matix2267
  • 620
  • 4
  • 11
  • If this was allowed, it would need kind of intriguing rules for cases when there's more than one variant possible. You would need to perform overload resolution on all possible conversion results, or something like that. It's convoluted enough as it is I think... :-) – Kos Jan 29 '12 at 13:01
  • @Kos: Actually all possible conversion paths are checked for overload resolution and they are ranked according to the type of conversions performed. If there's more than one top-ranked conversion path then the call is ambiguous. But in this case the compiler doesn't find any conversion path. – matix2267 Jan 29 '12 at 13:20

3 Answers3

5

Implicit conversions aren't performed on the first operand when a member function is matched. Just make your operator a non-member, perhaps a friend:

class C {
};

int operator-(C c, int x) {
    return 3-x;
}

From [over.match.oper]:

— If T1 is a complete class type, the set of member candidates is the result of the qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, the set of member candidates is empty.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
1

It doesn't compile (using GCC) because it would neet to chain two user-defined conversions to get from wrapper to int: first to C, then to int. The standard doesn't allow this. See David Rodriguez' answer in another thread.

Community
  • 1
  • 1
Lumi
  • 14,775
  • 8
  • 59
  • 92
  • I can see only one user-defined conversion there: `wrapper::operator int()`. `C::operator-(int)` is not a conversion nor does it require one. – matix2267 Jan 29 '12 at 13:25
0

When you do return wrap-3; the compiler dosn't know to convert wrapper to a C in order for the calculation to take place, it is looking for a operator- in wrapper, or a conversion in wrapper to a numeric type. Just because C has a operator- dosn't make the compiler implicitly convert to it, you could have multiple conversion operators in wrapper, which one should the compiler convert to?

Either explicitly tell the compiler to convert to C, of add the operator- to wrapper like this..

class wrapper {
  public:
    operator C() {
        static C z;
        return z;
    }

    int operator-(int x) {
        return C()-x;
    }
} wrap;
alegalle
  • 19
  • 2
  • I'd say the compiler would chose the only possible conversion. If I had another class D and wrapper was convertible to D then D coudn't have `operator-(int)` defined otherwise wrap-3 would be ambiguous. – matix2267 Jan 29 '12 at 13:27