Consider this code:
struct X{
explicit X(){}
explicit X(const X&){}
};
void foo(X a = X()){}
int main(){}
Using C++14 standard, both GCC 7.1 and clang 4.0 rejects the code, which is what I expected.
However, using C++17 (-std=c++1z
), they both accept the code. What rule changed?
For both compilers to exhibit this same behavior, I doubt this to be a bug. But as far as I can tell, the latest draft still says, default argument uses the semantics of copy-initialization 1. Again, we know that explicit
constructors will only allow direct initialization 2.
Because the behavior of copy elision changes from C++17; for this case the optimization is mandatory.
Under the following circumstances, the compilers are required to omit the copy- and move- constructors of class objects even if copy/move constructor and the destructor have observable side-effects:
In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
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 ofT
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.
来源:https://stackoverflow.com/questions/44154264/what-changes-to-c-made-copy-initialization-work-for-class-with-explicit-constr