模板的协方差规则

rules on convariance for templates

为什么 initializer_list<string> ls = {"A", "B", "C"}; 有效?

rhs是intializer_list<const char*>的,不知道怎么转成lhs的

同样,vector<string> vs = {"A", "B", "C"} 是如何工作的?

右边是intializer_list<const char*>

这是错误的。右侧没有类型。它不是 initializer_list 类型的对象。它是 braced-init-list,一种特殊的语言结构,用于多种上下文。

[dcl.init.list]/3 关于你的第一个问题是这样说的:

List-initialization of an object or reference of type T is defined as follows:
    [...]
— Otherwise, if T is a specialization of std::initializer_list<E>, a prvalue initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5).

[dcl.init.list]/5:

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated a temporary array of N elements of type const E, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible (Clause 11) in the context of the initializer list. —end note ] If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.

简而言之:

  1. 首先它为 3 个字符串的数组分配内存

  2. 然后它尝试用 init-list 中的相应元素初始化每个字符串。列表的所有元素都可以转换为 const char* 并且 std::string 具有接受 const char* 的构造函数,因此它用于构造这些字符串。

在你的第二个问题中,使用了 [dcl.init.list]/3 中的另一个子句:

List-initialization of an object or reference of type T is defined as follows:
[...]
— Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

vector<string> 有一个采用 initializer_list<string> 的构造函数。在这种情况下这是最佳匹配,我们回到阶段 1:我们需要从 braced-init-list 构造 initializer_list<string>,我们已经知道该怎么做。