tl;dr: The published C++14 text specified output 21
. However, the behaviour of this code was changed by CWG Issue 1467, which gained the status of Defect in November 2014.
Defect Reports are considered to apply retroactively. clang 3.7 and VS2015 have applied the resolution suggested by this defect report, which appears in C++17 drafts as of N4296.
Prior to this defect report, the behaviour was covered by this text from N4140 [over.match.list]:
When objects of non-aggregate class type T
are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
- Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
- If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
If the initializer list has no elements and T has a default constructor, the first phase is omitted. In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. [Note: This differs from other situations (13.3.1.3, 13.3.1.4), where only converting constructors are considered for copy-initialization. This restriction only applies if this initialization is part of the final result of overload resolution.
—end note ]
Your class is not an aggregate because it has a user-provided constructor.
The above text is directed-to by the following bullet point in [dcl.init.list]/3:
- Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7).
So, in the published C++14, the initializer-list constructor should actually be preferred to the copy-constructor, if it matches. C++11 had the same text.
In your question you say that C++14 contains:
If T
is a class type and the initializer list has a single element of type [...]
This text was not in C++14, but applied at a later date by a defect report. In the updated standard with the defect report applied (N4296), this appears as a bullet point higher up in the list of bullet points in [dcl.init.list]/3; so now the copy-constructor is selected ealier in the process and we do not get so far as the above [over.match.list] step.
Note that although the defect is titled List-initialization of aggregate from same-type object, the resolution actually affects initialization of both aggregates and non-aggregates.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…