C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?

C++: function call expression with braced-init-list - does standard prescribe to ignore braces in a trivial case of a single element list?

本文关键字:列表 元素 单个 微不足道 情况下 初始化 函数调用 标准 C++ 表达式 是否      更新时间:2023-10-16

请考虑以下示例:

class X;
void f(const X &);
void g()
{
X x;
f({x});
}

在这种情况下,标准是否要求实现忽略大括号?不涉及任何优化。如果是,则从哪个版本开始?

乍一看,根据规则,似乎应该有一个临时创建的 - 当然完全没有必要,但仍然如此。查看列表初始化,我找不到任何相关内容。X在这里不是聚合。

GCC 和 Clang,即使有-O0,也无需临时创建即可生成代码 - 即使X复制构造函数具有可观察到的副作用,即使X具有X(std::initializer_list<X>)构造函数。

f({x})X const &x(f的参数(的初始化是副本初始化上下文中的列表初始化,由[dcl.init]/15。因此,我们可以删除该函数,只问这意味着什么:

int main() {
X x;
X const &y = {x}; // still copy list initialization
}

现在,[dcl.init.list]中适用于此的第一个条款是[dcl.init.list]/3.9,它指出您基本上只需删除大括号。

。如果初始值设定项列表具有E类型的单个元素,并且 [此处X const&]T不是引用类型,或者其引用类型与E相关,则对象或引用从该元素初始化(通过复制初始化进行复制列表初始化,或通过直接初始化直接列表初始化(;....

X const&实际上是一个引用类型,但其引用的类型X const确实与初始值设定项的类型X相关,因此该子句仍然适用。现在我们只有

int main() {
X x;
X const &y = x; // (non-list/"plain") copy-initialization
}

当然,这不会调用X的构造函数(通过[dcl.init.ref]/5.1(。

请注意,上面的引用在您的 cpp首选项页面上也略有改写:

。(如果T不是类类型(,如果大括号的初始化列表只有一个元素,并且T不是引用类型,或者是引用类型与元素类型的基类相同或引用的类型,则T直接初始化(在直接列表初始化中(或复制初始化(在复制列表初始化中(,....

也许"T不是引用类型"或"T不是类类型"使它飞到了雷达下,但这是您要查找的子句,因为 a( 引用类型确实不是类类型和 b( "或......"在前提条件使其适用。从缺少版本控制框来看,这种行为将与列表初始化本身一样古老:自 C++11 以来。