为什么我们不能使用std::initializer_list的对象来初始化数组?

6
请先考虑下面的例子:
#include <iostream>
#include <initializer_list>
#include <vector>
#include <array>
#include <set>

int main(){
   std::initializer_list il1={1,2,3,4,5}; 
   std::initializer_list il2{1,2,3,4,5}; 
                                    
    std::vector<int> v1 = il1;  //this work - by means of COPY 
    std::set<int> s1 = il1;     //this work - by means of COPY

    std::array<int, 5> a1 = {1,2,3,4,5};  //this work
    std::array<int, 5> a2 = il1;      //this didn't work? - not compatable ?
    int array1[5] = {1,2,3,4,5};          //this work
    int array2[5] = il2;              //this didn't work? - not compatable ?                               
}

为什么我们不能在示例中使用std::initializer_list的对象来初始化数组?
我遇到了这个错误:
<source>: In function 'int main()':
<source>:15:29: error: conversion from 'std::initializer_list<int>' to non-scalar type 'std::array<int, 5>' requested
   15 |     std::array<int, 5> a2 = il1;      //this didn't work? - not compatable ?
      |                             ^~~
<source>:17:21: error: array must be initialized with a brace-enclosed initializer
   17 |     int array2[5] = il2;              //this didn't work? - not compatable ?
      |  

而且在 il1 (在 std::initializer_list il1={1,2,3,4,5};) 和单独的 {1,2,3,4,5} 之间是否有任何特定差异?


2
因为普通数组和std::array都是聚合体,而聚合体只能使用聚合初始化进行初始化。不可能使用其他无关的对象进行聚合初始化。普通数组甚至不能进行复制初始化(所以例如int array3[5] = array1;是不可能的)。然而,std::array允许使用相同类型的另一个std::array对象进行复制语义。 - Some programmer dude
1
什么错误?它包含了很有价值的信息。现在的编译器错误能够告诉你很多关于为什么出错,甚至有时还能告诉你如何修复。 - 463035818_is_not_an_ai
1
请在问题中包含编译器错误信息。实际上,没有合适的用户转换。这就是错误的原因。所以你的问题归结为:数组、setvector之间有什么区别?一旦你理解了为什么对于setvector有效,你就会明白为什么对于array无效。 - 463035818_is_not_an_ai
1
@463035818_is_not_an_ai 你对这个回答的修改后的形式有什么看法?我应该取消删除吗? - Ted Lyngmo
1
如果你遇到了那个错误,那么你的代码中什么都“不起作用”。 - 463035818_is_not_an_ai
显示剩余9条评论
1个回答

5

std::vector具有初始化列表构造函数

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

(constexpr自C++20起)

std::set有一个初始化列表构造函数

set( std::initializer_list<value_type> init, const Compare& comp = Compare(), const Allocator& alloc = Allocator() );

(自C++14以来,还有另一个委托构造函数) std::array没有用户定义的构造函数(将“用户”理解为“非编译器生成的”)。它是一个聚合体。
这个
std::array<int, 5> a1 = {1,2,3,4,5}; 
int array1[5] = {1,2,3,4,5}; 

聚合初始化。这里的{1,2,3,4,5}是一个普通的初始化列表(这是cppreference的称呼,不确定是否是官方术语)。它不是一个std::initializer_list

当构造一个std::initializer_list时,有特殊规则。详细信息请参考链接。例如:

std::vector<int> v1{1,2,3,4,5};

这个调用了上面的构造函数。一个`std::initializer_list`从`{1,2,3,4,5}`创建出来,但只是因为`std::vector`有一个接受`std::initializer_list`的构造函数。
附注:如果你想知道为什么规则有点奇怪,回想一下,在C++11之前,不可能像`std::vector v1{1,2,3,4,5};`这样直接使用,而`int array1[5] = {1,2,3,4,5};`早就存在了。必须添加一些新的东西,即`std::initializer_list`和它们被创建时的一些特殊规则。
再附注:很少情况下,你需要显式构造一个`std::initializer`,就像你在代码中所做的那样。粗略地说,它们只是语法`{1,2,3,4,5}`和某种特殊类型的构造函数之间的粘合剂。

1
将"user"解读为"...,而不是由标准库代码提供"。我认为"由标准库代码提供"也算是用户定义的,否则std::中的任何东西都不能有用户定义的构造函数,一切都会成为聚合体。:P - HolyBlackCat
1
@HolyBlackCat 谢谢你发现了,那里多了一个“不”。我的意思是将“user”读作“(不是编译器生成的)/(由库代码提供的)”,但是直接删除可能更清楚一些。 - 463035818_is_not_an_ai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接