In [dcl.init]/17.6, it is explicitly written that for the case of parenthesis initialization, copy elision occurs:
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. [ Example: T x = T(T(T())); calls the T default constructor to initialize x. — end example ]
But in the case of list-initialization, for which the above paragraph does not apply, I did not find anything similar. See [dcl.init.list].
So why is there copy elision in this case: T x{T(T())};
according to the C++17 standard.
There is no copy elision in such case according to the current draft.
Consider the following example:
#include <iostream>
#include <initializer_list>
struct S {
S() {std::cout << "default\n";}
S(const S&) {std::cout << "copy\n";}
S(std::initializer_list<S>) {std::cout << "initializer list\n";}
};
int main()
{
S s = S{S()};
}
According to Core Language Issue 2137, the constructor taking std::initializer_list
as parameter should be chosen (Clang may choose copy constructor or perform copy elision here, which is incorrect). So constructors are intended to be taken into consideration for such list initialization.
The problem is that when copy/move constructor is selected, it is reasonable to elide this copy/move. In fact, Core Language Issue 2327 has already addressed this defect.