c++ - 为什么 ctor 中的 std::initializer_list 没有按预期运行?
问题描述
#include <vector>
int main()
{
auto v = std::vector{std::vector<int>{}};
return v.front().empty(); // error
}
见在线演示
然而,根据 Scott Meyers 的Effective Modern C++(强调原文):
但是,如果一个或多个构造函数声明一个类型为 的参数
std::initializer_list
,则使用大括号初始化语法的调用强烈倾向于采用 的重载std::initializer_lists
。强烈。如果编译器有任何方法可以将使用大括号初始化程序的调用解释为采用 a 的构造函数std::initializer_list
,编译器将采用该解释。
所以,我认为std::vector{std::vector<int>{}};
应该产生一个对象std::vector<std::vector<int>>
而不是std::vector<int>
.
谁错了?为什么?
解决方案
Meyers 大部分是正确的(例外是T{}
如果存在默认构造函数则进行值初始化),但他的陈述是关于重载决议的。这发生在 CTAD 之后,CTAD 选择要使用的类(以及构造函数集)。
CTAD 不“更喜欢”初始化列表构造函数,因为它更喜欢复制而不是包装可嵌套模板,如std::vector
or std::optional
。(可以用推导指南覆盖它,但标准库使用默认值,正如人们所期望的那样。)这在一定程度上是有道理的,因为它可以防止创建奇怪的类型,例如std::optional<std::optional<int>>
,但它使通用代码更难编写,因为它
template<class T> void f(T x) {
std::vector v{x};
// …
}
一种以不规则和非内射方式取决于其论点类型的含义。特别是,v
可能是std::vector<int>
with T
=int
或 with T
= std::vector<int>
,尽管是std::vector<std::deque<int>>
if T
= std::deque<int>
。不幸的是,基于其他一些类型计算一种类型的工具不能在通用上下文中使用。
推荐阅读
- vue.js - 我应该使用
或者 为 div? - c# - PowerBi 无法使用 authToken 加载报告
- python - 使用 pyserial 与 COM 端口通信,但设备无法正确解释命令
- laravel-artisan - laravel8-php artisan serve 命令错误
- python - 从 Jupyter 运行代码时遇到问题(未定义名称“pkg_resources”)
- sql-server - 如何在 SSMS 中创建第一个服务器实例
- django - 循环通过 Beautiful Soup 结果
- datarow - 如何修复数据集合中数据行的后期绑定,其中数据行变量在范围内定义
- android - (Camera2 API)我可以同时运行 2 个不同配置的 ImageReader 实例吗?
- mysql - 如何从 sql 中的名称对中选择不同的值?