Because the behavior of copy elision changes from C++17; for this case copy elision is mandatory.
Mandatory elision of copy/move operations
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:
In the initialization of an object, when the initializer expression is
a prvalue of the same class type (ignoring cv-qualification) as the
variable type:T f() { return T(); } T x = T(T(f())); // only one call to default constructor of T, to initialize x
Note: the rule above does not specify an optimization: C++17 core language specification of prvalues and temporaries is fundamentally different from that of the earlier C++ revisions: there is no longer a temporary to copy/move from. Another way to describe C++17 mechanics is “unmaterialized value passing”: prvalues are returned and used without ever materializing a temporary.
And for copy initialization:
The effects of copy initialization are:
First, if
T
is a class type and the initializer is a prvalue
expression whose cv-unqualified type is the same class asT
, the
initializer expression itself, rather that a temporary materialized
from it, is used to initialize the destination object: see copy
elision (since C++17)If
T
is a class type and the cv-unqualified version of the type of
other isT
or a class derived fromT
, the non-explicit constructors of
T
are examined and the best match is selected by overload resolution.
The constructor is then called to initialize the object.
That means for X a = X()
, a
will be default constructed directly, the copy/move constructors and their side effects will be omiited completely. The selection of non-explicit constructors for overload resolution won’t take place, which is required in C++14 (and before). For these guaranteed cases, the copy/move constructors don’t participate in, then it won’t matter whether they’re explicit
or not.