Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

explicit deleted constructors - does this matter?

When marking a constructor as deleted, i.e.

class MyClass {

   // ... 

   MyClass(int x) = delete;

   // ... 

};

is there any effect to marking the deleted constructor as explicit? i.e.

   explicit MyClass(int x) = delete;

?

like image 806
einpoklum Avatar asked Dec 07 '25 08:12

einpoklum


1 Answers

Yes, = delete does not affect overload resolution, except that if in the end overload resolution would choose an overload that is deleted, then the overload resolution will be considered ill-formed. = delete does not modify the decision making process for overload resolution.

explicit does affect overload resolution substantially in that it changes whether the constructor will participate as candidate in different overload resolution scenarios.

The two constructs are orthogonal. One does not imply the other should be added or dropped.


Example:

struct MyClass {
    MyClass(int x) = delete;
    MyClass(long x) { };
};

Without explicit on the first constructor, MyClass x = 0; is ill-formed, because overload resolution would prefer the first constructor. With explicit the first constructor is not considered for the copy-initialization and the second one (which otherwise would be a worse match) is chosen. The initialization will not be ill-formed.

On the other hand, for an initialization of the form MyClass x(0);, which is direct-initialization, all constructors are always considered and overload resolution will choose the first one, regardless of whether it is explicit or not. Therefore this initialization will always be ill-formed.

So, in this example, you need to decide whether you want to make only explicit conversion from int ill-formed (while still allowing implicit and explicit conversion from long) or whether you want to make implicit and explicit conversion from long ill-formed.


Even if this is the only constructor for the class, there is still a difference.

Suppose there is a function overload set

void f(MyClass);
void f(A);

with

struct MyClass {
    explicit MyClass(int x) = delete;
};

struct A {
    A(int x) {};
};

Then trying to call f(0) is well-formed, because the first overload is non-viable. explicit constructors are not considered for implicit conversion sequences for function arguments in overload resolution. Only the second overload is viable and will be chosen.

But if there is no explicit, then both overloads become viable and the overload resolution will be ambiguous. That the constructor is deleted doesn't matter for this determination.


Deleting a constructor means that you want a specific overload resolution result to cause the initialization to be ill-formed. When making the decision which form you want to be ill-formed you always have to consider whether or not explicit should be applied, just like when defining non-deleted overloads.

like image 91
user17732522 Avatar answered Dec 10 '25 07:12

user17732522



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!