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

问题描述

考虑以下示例:

class X;

void f(const X &);

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

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

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

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

标签: c++list-initialization

解决方案


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

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

现在,[dcl.init.list]适用于 this 的第一个子句是[dcl.init.list]/3.9,它表明您基本上只是放下大括号。

...如果初始化列表有一个类型的元素E并且T[这里X const&] 不是引用类型或其引用类型与引用相关E,则从该元素初始化对象或引用(通过复制初始化复制-列表初始化,或通过直接初始化直接列表初始化);……

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

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

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

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

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

也许“T不是引用类型”或“T不是类类型”使这在雷达下飞行,但这是您正在寻找的子句,因为a)引用类型确实不是类类型,b)先决条件中的“或...”使其适用。从缺少版本控制框来看,这种行为与列表初始化本身一样古老:从 C++11 开始。


推荐阅读