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

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

考虑以下示例:

class X;

void f(const X &);

void g()
{
    X x;
    f({x});
}

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

乍一看,按照规则似乎应该创建一个临时文件——当然完全没有必要,但仍然如此。查看 list initialization 我找不到任何相关内容。 X 这里不是聚合。

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

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

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

现在,[dcl.init.list] 中第一个适用于此的子句是 [dcl.init.list]/3.9,它声明您基本上只是去掉大括号。

... if the initializer list has a single element of type E and either T [here X const&] is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); ....

X const&实际上是一个引用类型,但它的引用类型X const确实与初始化器的类型X有关,所以该子句仍然适用。现在我们只有

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

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

请注意,上面的引述在您的 cppreference 页面上也略有改写:

... (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type whose referenced type is same as or is a base class of the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), ....

也许“T 不是引用类型”或“T 不是 class 类型”使它不为人知,但这是您的条款正在寻找,因为 a) 引用类型确实不是 class 类型,并且 b) 先决条件中的 "or ..." 使其适用。从缺少版本控制框来看,这种行为与列表初始化本身一样古老:自 C++11 以来。