gpt4 book ai didi

C++ 复制构造函数被调用而不是 initializer_list<>

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:20:39 25 4
gpt4 key购买 nike

基于这段代码

struct Foo 
{
Foo()
{
cout << "default ctor" << endl;
}

Foo(std::initializer_list<Foo> ilist)
{
cout << "initializer list" << endl;
}

Foo(const Foo& copy)
{
cout << "copy ctor" << endl;
}
};

int main()
{

Foo a;
Foo b(a);

// This calls the copy constructor again!
//Shouldn't this call the initializer_list constructor?
Foo c{b};



_getch();
return 0;
}

输出是:

默认构造函数

抄袭者

抄袭者

在第三种情况下,我将 b 放入应该调用 initializer_list<> 构造函数的大括号初始化中。

相反,复制构造函数带头。

你们有人能告诉我这是如何工作的吗?为什么?

最佳答案

正如 Nicol Bolas 所指出的,此答案的原始版本是不正确的:撰写本文时的 cppreference 错误地记录了在列表初始化中考虑构造函数的顺序。以下是使用标准 n4140 草案中存在的规则的答案,该标准非常接近官方 C++14 标准。

原答案的文字仍然包含在内,以备记录。


更新的答案

根据 NathanOliver 的评论,gcc 和 clang 在这种情况下会产生不同的输出:

g++ -std=c++14 -Wall -pedantic -pthread main.cpp && ./a.out
default ctor
copy ctor
copy ctor
initializer list


clang++ -std=c++14 -Wall -pedantic -pthread main.cpp && ./a.out
default ctor
copy ctor
copy ctor

gcc 是正确的。

n4140 [dcl.init.list]/1

List-initialization is initialization of an object or reference from a braced-init-list.

你在那里使用了列表初始化,因为c是一个对象,其列表初始化规则在 [dcl.init.list]/3 中定义:

[dcl.init.list]/3:

List-initialization of an object or reference of type T is defined as follows:

  1. If T is an aggregate...
  2. Otherwise, if the initializer list has no elements...
  3. Otherwise, if T is a specialization of std::initializer_list<E>...

到目前为止浏览列表:

  1. Foo不是一个集合。
  2. 它只有一个元素。
  3. Foo不是 std::initializer_list<E> 的特化.

然后我们点击 [dcl.init.list]/3.4:

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). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

现在我们有所进展。 13.3.1.7 也称为 [over.match.list]:

Initialization by list-initialization
When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

  1. 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.
  2. 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.

因此,在重载决议的第二阶段,复制构造函数将仅在初始化列表构造函数之后被考虑。此处应使用初始化列表构造函数。

值得注意的是 [over.match.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.

在 [dcl.init.list]/3.5 处理单元素列表初始化之后:

Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element; if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.

这解释了 cppreference 在何处获得了单元素列表初始化的特殊情况,尽管他们将其置于比应有的顺序更高的位置。


原始答案

您遇到了列表初始化的一个有趣方面,如果列表满足某些要求,它可能会被视为复制初始化而不是列表初始化。

来自 cppreference :

The effects of list initialization of an object of type T are:

If T is a class type and the initializer list has a single element of the same or derived type (possibly cv-qualified), the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization). (since c++14)

Foo c{b}满足所有这些要求。

关于C++ 复制构造函数被调用而不是 initializer_list<>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52000082/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com