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 &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
,它声明您基本上只是去掉大括号。
... 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 以来。
考虑以下示例:
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 &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
,它声明您基本上只是去掉大括号。
... if the initializer list has a single element of type
E
and eitherT
[hereX const&
] is not a reference type or its referenced type is reference-related toE
, 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 eitherT
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 以来。