首页 > 解决方案 > 关于在 C++ 中使用 { } 初始化向量

问题描述

在 Stroustrup 的《编程:使用 C++ 编程的原则和实践(第二版)》一书中,作者在自己的结构中创建了三个向量,如下所示:

struct Day {
    vector<double> hour{ vector<double>(24,not_a_reading) };
};

struct Month { // a month of temperature readings
    int month{ not_a_month }; // [0:11] January is 0
    vector<Day> day{ 32 }; // [1:31] one vector of readings per day
};

struct Year { // a year of temperature readings, organized by month
    int year; // positive == A.D.
    vector<Month> month{ 12 }; // [0:11] January is 0
};

我的问题是,为什么要vector<Day> day{32};创建一个大小为 32 的 Day 类型的向量,而vector<int>{32};创建一个大小为 1 的向量?

标签: c++vectorconstructorinitializationlist-initialization

解决方案


当初始化程序是初始化程序列表时,首先考虑接受 std::initializer_list 的构造函数。

所以对于这个声明

std::vector<int> v{32};

这里使用了 std::vector 类的 constrictor,它具有类型std::initializer_list<T> 的第一个参数。

vector(initializer_list<T>, const Allocator& = Allocator());

在这种情况下,std::initializer_list<int>只包含一个等于 32 的元素。

在这份声明中

std::vector<Day> day{32};

初始化列表 {32} 无法转换为std::initializer_list<Day>. 所以接受初始化列表的构造函数是不合适的。

在这种情况下,编译器会考虑另一个构造函数并找到接受整数作为向量中元素数的构造函数。

explicit vector(size_type n, const Allocator& = Allocator());

注意这个构造函数是显式的。所以例如你不能写

std::vector<Day> day = {32};

来自 C++ 17 标准(13.3.1.7 通过列表初始化进行初始化)

1 当非聚合类类型 T 的对象被列表初始化,使得 8.5.4 指定根据本节中的规则执行重载解析时,重载解析分两个阶段选择构造函数

(1.1) —最初,候选函数是类 T 的初始化器列表构造函数 (8.5.4),参数列表由初始化器列表作为单个参数组成。

(1.2) —如果没有找到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数是类 T 的所有构造函数,参数列表由初始化列表的元素组成。


推荐阅读