我遇到了this一篇文章,其中我在其中一张海报中读到了这个例子。为方便起见,我在这里引用了这一点。
struct Foo
{
Foo(int i) {} // #1
Foo() {}
};
int main()
{
std::vector<Foo> f {10};
std::cout << f.size() << std::endl;
}
如上所述,上面的代码发出“1”(10是由a转换为Foo 获取int的构造函数,然后是vector的initializer_list 构造函数被调用)。如果我注释掉被评为#1的行,那么 结果是“10”(初始化器列表无法转换为int 使用了构造函数)。
我的问题是,如果删除了int构造函数,为什么它会发出10。 我知道统一初始化列表按以下顺序工作
1-Calls the initializer list if available or possible
2-Calls the default constructor if available
3-Does aggregate initialization
在上面的例子中,为什么在向量中创建10个项目,因为1,2和3是不可能的?这是否意味着统一初始化项目的向量可能总是有不同的行为?
答案 0 :(得分:3)
借用Scott Meyers在Effective Modern C ++中的引用(强调原文):
但是,如果一个或多个构造函数声明类型为
std::initializer_list
的参数,则使用支撑初始化语法的调用非常喜欢使用std;:initializer_list
s的重载。 强烈。如果以任何方式让编译器将使用支撑初始值设定项的调用解释为采用std::initializer_list
的构造函数,编译器将采用该解释。
因此,当您拥有std::vector<Foo> f {10};
时,它会尝试使用vector<Foo>
的{{1}}构造函数。如果initializer_list<Foo>
可以从Foo
构建,那就是我们正在使用的构造函数 - 所以我们最终得到一个int
构建的Foo
。
或者,从标准,[over.match.list]:
当非聚合类类型
10
的对象被列表初始化(8.5.4)时,重载决策选择构造函数 分两个阶段:(1.1) - 最初,候选函数是类
T
的初始化列表构造函数(8.5.4)和 参数列表由初始化列表作为单个参数组成 (1.2) - 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中 候选函数是类T
的所有构造函数,参数列表由元素组成 初始化列表。
如果是一个可行的初始化列表构造函数,则使用它。如果你没有T
构造函数,那么就没有可行的初始化列表构造函数,并且第二次重载解析会找到Foo(int )
的构造函数需要一个大小 - 所以你'得到一个10个默认构造的vector
的向量。