Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C
would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.
(Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)
Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:
struct B;
struct A
{
A(int);
A operator +(B) const;
};
struct B
{
B(int);
B operator +(B) const;
};
Now, what should 1 + B{3}
do? Apparently, it could be transformed to B{1} + B{3}
. But who's to say we couldn't do A{1} + B{3}
instead? Why would B
's constructor be preferred over A
's? Of course, we could argue that either B
is to be preferred, because, look at how nice and symmetric B{...}+B{...}
is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B
's constructor was made explicit
– should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A
?
Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator +
in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl
, implcitly convert an operand to it, and then perform an operation on that.
Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).
TL;DR:
- There are tricky corner cases.
- The benefit is marginal (why not make such operators free functions as others have pointed out)?
- The discussions on how to standardize this would certainly be long.