Implicit VS Explicit Conversion

Solution 1:

one uses a Y's constructor and one uses the assignment operator though.

Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=) is never called; instead, a non-explicit one-parameter constructor (that accepts the type X as a parameter) is called.

The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.

Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.

In this case, only one-parameter constructors not marked with explicit are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.

As specified in this other answer, any constructor not marked as explicit can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y with x, but x first has to be converted to type Y, which is done with the implicit constructor.

This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit) constructor from a const char *: any function that receives a string parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string object.

Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.

You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.

More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.

Solution 2:

The first form is direct initialization. The second is copy initialization.

Copy initialization implicitly calls a converting constructor or conversion operator and then explicitly calls a copy constructor (the copy constructor call may be elided, but an accessibility check must still be performed).

Consider a third possibility, which is copy-initialization, but the conversion is explicit:

Y y = Y(x);

or

Y y = (Y)x;

Solution 3:

one uses the assignment operator though

No, it does not. It calls the constructor directly.

The reason why one is explicit and one is implicit is because implicit conversions can happen when you don't want them to. Explicit ones cannot. The easiest example of this is bool.

Let's say that you invent some type which can be either true or false- like a pointer. Then let's further say that you decide that in order to make life easier for your users, you let it convert to bool implicitly. This is great- right up until the point where one of your users does something dumb.

int i = 0;
i = i >> MyUDT();

Oh wait- why does that even compile? You can't shift a MyUDT at all! It compiles because bool is an integral type. The compiler implicitly converted it to a bool, and then to something that can be shifted. The above code is blatantly dumb- we only want people to be able to convert to a bool, not a bool and anything else that a bool might want to do.

This is why explicit conversion operators were added to C++0x.