相同类型的对象的列表初始化优先级 [英] List-initialization priority from object of same type
问题描述
#include <iostream>
#include <initializer_list>
using namespace std;
struct CL
{
CL(){}
CL (std::initializer_list<CL>){cout<<1;}
CL (const CL&){cout<<2;}
};
int main()
{
CL cl1;
CL cl2 {cl1}; //prints 21
}
这里是 CL struct复制构造函数和初始化列表构造函数。我想只有复制构造函数必须在这里调用,因为根据C ++ 14 Standard,8.5.4 / 3
Here is CL struct with copy constructor and initializer-list constructor. I think only copy constructor must be called here, because according to C++ 14 Standard, 8.5.4/3
列表初始化一个对象或类型T的引用被定义为
如下:
- 如果T是类类型,并且初始化器列表具有
类型为cv U的单元素,其中U是T或一个从T派生的类,
对象从该元素初始化(通过复制初始化
进行拷贝列表初始化,或通过直接初始化
直接列表初始化)。
- 否则...
List-initialization of an object or reference of type T is defined as follows:
— If T is a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).
— Otherwise, ...
换句话说, cl2 必须从 cl1 元素执行,而不是从initializer-list {cl1} 执行。 Clang和gcc都打印21,只有Visual Studio打印2,我认为是正确的。
有两个候选构造函数用于接受类型CL的参数 cl1
1)具有 std :: initializer_list< CL>
的构造函数(因为没有从CL到 std :: initializer_list< ; CL>
)
2)复制构造函数const CL& (完全匹配只有限定转换非const-> const)
In other words, the initialization of cl2 must be performed from cl1 element, but not from the initializer-list {cl1}. Clang and gcc both print "21", only Visual Studio prints "2" and I think it's correct.
There are two candidate constructors for taking an argument cl1 of type CL:
1) Constructor with std::initializer_list<CL>
(passes because no such conversion from CL to std::initializer_list<CL>
)
2) Copy constructor with const CL& (exact match with only qualification conversion non-const->const)
谁是对的?谁的行为是正确的?
Who is right? Whose behavior is correct?
感谢
推荐答案
tl; dr: strong>发布的C ++ 14文本指定输出 21
。但是,此代码的行为已更改 CWG Issue 1467 ,它于2014年11月获得了缺陷状态。
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.
缺陷报告被认为是追溯适用的。 clang 3.7和VS2015已应用此缺陷报告建议的解决方案,它在N4296中出现在C ++ 17草稿中。
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.
在此缺陷报告之前,该行为由N4140 [over.match.list]的文本覆盖:
Prior to this defect report, the behaviour was covered by this text from N4140 [over.match.list]:
非聚合类类型
T
列表初始化(8.5.4),重载解析选择两个阶段的构造函数:
When objects of non-aggregate class type
T
are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
- 最初,候选函数是类T的初始化列表构造函数(8.5.4),参数列表由作为单个参数的初始化列表组成
- 如果没有找到可行的初始化列表构造函数,则会再次执行重载解析,其中候选函数是类T的所有构造函数,参数列表由元素初始化列表。
如果初始化器列表没有元素,T具有默认构造函数,则省略第一阶段。在复制列表初始化中,如果选择显式构造函数,初始化是不成形的。 [注意:这不同于其他情况(13.3.1.3,13.3.1.4),其中只考虑转换构造函数用于复制初始化。此限制仅适用于此初始化是过载分辨率的最终结果的一部分。
-end note]
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.
上述文本由[dcl.init.list] / 3中的以下项目符号指向:
The above text is directed-to by the following bullet point in [dcl.init.list]/3:
- 否则,如果T是类类型,则考虑构造函数。适用的构造函数被枚举,并且通过重载分辨率(13.3,13.3.1.7)选择最好的构造函数。
因此,在发布的C ++ 14中,initializer-到复制构造函数,如果它匹配。 C ++ 11有相同的文本。
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.
在你的问题中,你说C ++ 14包含:
In your question you say that C++14 contains:
如果
T
是类类型,并且初始化器列表有一个类型为[。 ..]
If
T
is a class type and the initializer list has a single element of type [...]
此文本不是在C ++ 14中,而是在以后由缺陷报告应用。在应用了缺陷报告的更新标准(N4296)中,这在[dcl.init.list] / 3中的项目符号列表中显示为更高的项目符号点;所以现在复制构造函数在过程中被选择为ealier,并且我们没有达到上面的[over.match.list]步骤。
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.
这篇关于相同类型的对象的列表初始化优先级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!