User implicit conversion of operator overloaded arguments

In my Term class, the following operator overload is defined:

 public static Term operator *(int c, Term t) {...} 

This class also defines an implicit conversion from Variable to Term :

 public static implicit operator Term(Variable var) {...} 

I would like to understand why the following does not compile:

 static void Main(string[] args) { Variable var = ...; // the details don't matter Console.WriteLine(2 * var); // var isn't implicitly converted to Term... Console.ReadKey(); } 

The compiler says:

The operator '*' cannot be applied to operands of type 'int' and 'OOSnake.Variable'

Why is my operator * overload not found?

EDIT . As suggested in the comments, here is a small example that repeats the error:

 namespace Temp { class A { } class B { public static implicit operator B(A a) { return new B(); } public static B operator *(int c, B b) { return new B(); } } class Program { static void Main(string[] args) { Console.WriteLine(2 * new A()); } } } 
+5
source share
3 answers

In principle, allowing operator overloading does not include implicit user conversions to find operators that may be applicable.

From section 7.3.4 of the C # 5 specification:

An operation of the form x op y , where op is an overloaded binary operator, x is an expression of type x , and y is an expression of type y , is processed as follows:

  • The set of user-defined operators provided by x and y for the op(x, y) operator is defined. The set consists of a combination of candidate operators provided by X and candidate operators provided by y , each of which is determined using the rules of ยง7.3.5. If x and y are of the same type, or if x and y derived from a common base type, then common candidate operators occur only in the combined set once.

And 7.3.5 does not include implicit user conversions when looking for a set of statements.

Please note that this also will not work if the implicit conversion to Term was declared in the Variable class, although it would be more reasonable to specify and implement it, since the compiler could look at the set of transformations from the operand type for other types and use it to resolve overloading.

However, this is only a matter of finding operators. The compiler gladly performs implicit conversions when it considers whether overload is applicable. For example, in your case, if you add:

 class A { public static B operator *(A a, B b) { return new B(); } } 

Then this is true:

 A a = new A(); Console.WriteLine(a * a); 
+4
source

Console.WriteLine (2 * var) does not contain a hint that you will want to convert var to type Term. The compiler sees the int and multiplication operator and a variable of type "Variable".

Edit: To clarify, for your example to work, the compiler had to go through all types in scope and see if a simple conversion from type "A" takes place.

And if it also happens that class C is like:

 class C { public static implicit operator C(A a) { return new A(); } public static B operator *(int i, C c) { return new C(); } } 

it does not say what will happen.

This is why the compiler does not do this :)

+1
source

If you want your example to work, you must move the implicit statement that converts A to B to class A, for example:

 namespace Temp { class A { public static implicit operator B(A a) { return new B(); } } class B { public static B operator *(int c, B b) { return new B(); } } class Program { static void Main(string[] args) { Console.WriteLine(2 * ((B)new A())); } } } 

But you cannot use this 2 * new A() , because (Jon Skeet answer):

In principle, allowing operator overloading does not include implicit user conversions to find operators that may be applicable.

fooobar.com/questions/1237674 / ...

0
source

Source: https://habr.com/ru/post/1237674/


All Articles