#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
或std::optional
。(可以使用推导指南覆盖它,但标准库使用默认值,正如人们所期望的那样。)这在一定程度上可以防止创建奇怪的类型,例如std::optional<std::optional<int>>
,但它使泛型代码更难编写,因为它提供
template<class T> void f(T x) {
std::vector v{x};
// …
}
一种以不规则和非注入方式取决于其论点类型的含义。特别是,v
可能std::vector<int>
与T
=int
或与T
= std::vector<int>
,尽管是std::vector<std::deque<int>>
if T
= std::deque<int>
。不幸的是,基于其他一些类型计算一种类型的工具在通用上下文中不可用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句