gpt4 book ai didi

c++ - 双括号初始化

转载 作者:可可西里 更新时间:2023-11-01 15:19:45 33 4
gpt4 key购买 nike

下面的代码应该调用哪个构造函数,为什么?

struct S
{
int i;
S() = default;
S(void *) : i{1} { ; }
};

S s{{}};

如果我使用 clang (来自主干),然后调用第二个。

如果第二个构造函数被注释掉,那么S{{}}仍然是有效的表达式,但是(我相信)来自 S{} 的默认构造实例的移动构造函数在这种情况下被调用。

为什么在第一种情况下转换构造函数优先于默认构造函数?

S的构造函数这样组合的用意|就是保存它的std::is_trivially_default_constructible_v< S >属性,除了一组有限的情况,当它应该以某种方式初始化时。

最佳答案

If the second constructor is commented out, then S{{}} is still valid expression, but (I sure) move-constructor from default-constructed instance of S{} is called in the case.

实际上,情况并非如此。 [dcl.init.list] 中的顺序是:

List-initialization of an object or reference of type T is defined as follows:
— If T is an aggregate class and the initializer list has a single element of type cv U, [...]
— Otherwise, if T is a character array and [...]
— Otherwise, if T is an aggregate, aggregate initialization is performed (8.6.1).

一旦删除了 S(void *) 构造函数,S 就变成了一个集合——它没有用户提供的构造函数。 S() = default 由于某些原因不算作用户提供。来自 {} 的聚合初始化将最终对 i 成员进行值初始化。


Why conversion constructor has priority over the default one in the very first case?

void* 剩余的情况下,让我们继续往下看项目符号列表:

— Otherwise, if the initializer list has no elements [...]
— Otherwise, if T is a specialization of std::initializer_list, [...]
— 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).

[over.match.list] 给了我们一个两阶段的重载解决过程:

— Initially, the candidate functions are the initializer-list constructors (8.6.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.

S 没有任何初始化列表构造函数,因此我们进入第二个项目符号并使用 {} 的参数列表枚举所有构造函数。我们有多个可行的构造函数:

S(S const& );
S(S&& );
S(void *);

转换序列在[over.ics.list]中定义:

Otherwise, if the parameter is a non-aggregate class X and overload resolution per 13.3.1.7 chooses a single best constructor C of X to perform the initialization of an object of type X from the argument initializer list:
— If C is not an initializer-list constructor and the initializer list has a single element of type cv U, [...] — Otherwise, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.

Otherwise, if the parameter type is not a class: [...] — if the initializer list has no elements, the implicit conversion sequence is the identity conversion.

S(S&& )S(S const& )构造函数都是自定义转换序列加恒等转换。但是S(void *)只是身份转换。

但是,[over.best.ics] 有这个额外的规则:

However, if the target is
the first parameter of a constructor or
— the implicit object parameter of a user-defined conversion function
and the constructor or user-defined conversion function is a candidate by
— 13.3.1.3, when [...]
— 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), or
the second phase of 13.3.1.7 when the initializer list has exactly one element that is itself an initializer list, and the target is the first parameter of a constructor of class X, and the conversion is to X or reference to (possibly cv-qualified) X,

user-defined conversion sequences are not considered.

这排除了将 S(S const&)S(S&& ) 作为候选对象的考虑 - 它们正是这种情况 - 目标是构造函数的第一个参数[over.match.list] 第二阶段的结果和目标是对可能的 cv 限定 S 的引用,并且这样的转换序列将是用户定义的。

因此,唯一剩下的候选者是 S(void *),因此它是最可行的候选者。

关于c++ - 双括号初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42586836/

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