相同类型的对象的列表初始化优先级 [英] List-initialization priority from object of same type

查看:167
本文介绍了相同类型的对象的列表初始化优先级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆