C++ 为什么双空大括号{{}会创建std::initializer\u list<;双倍>;只有一个元素,而不是零?

C++ 为什么双空大括号{{}会创建std::initializer\u list<;双倍>;只有一个元素,而不是零?,c++,initializer-list,C++,Initializer List,我有以下构造函数: MyItem(std::initializer_list<double> l) { std::cout << "l size " << l.size() << ")" << std::endl; } l.size()给出的结果是1 这种行为背后的机制是什么 嵌套的{}看起来像是唯一元素的默认构造函数,但我不太明白类型推断在这里的工作原因和方式。当您使用大括号(列表初始化)初始化MyItem对象时,您显示的列

我有以下构造函数:

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}
l.size()给出的结果是1

这种行为背后的机制是什么

嵌套的{}看起来像是唯一元素的默认构造函数,但我不太明白类型推断在这里的工作原因和方式。

当您使用大括号(列表初始化)初始化
MyItem
对象时,您显示的列表构造函数非常贪婪

这些将传递一个空列表:

MyItem foo({});
MyItem foo{std::initializer_list<double>{}};
这是因为在某些上下文中,您可以简单地使用大括号代替已知类型。这里,它通过首选列表构造函数知道给定的列表应该包含
double

为了完整性,这看起来像是传递了一个空列表,但如果它有一个默认构造函数(或者在特殊情况下,做了一些几乎等价的事情),它实际上会初始化
foo
。如果没有默认构造函数,它将选择列表构造函数

这句话

MyItem{{}}
表示显式类型转换(函数表示法)

根据C++标准(5.2.3显式转换(函数表示))< /P>

  • 类似地,简单类型说明符或类型名说明符后跟 带括号的init list创建指定类型的临时对象 使用指定的带括号的初始列表初始化直接列表(8.5.4), 它的值是作为prvalue的临时对象
  • 类MyItem具有转换初始值设定项列表构造函数

    MyItem(std::initializer_list<double> l) {
        std::cout << "l size " << l.size() << ")" << std::endl;
    }
    
    因此,构造函数将获得一个包含一个元素的初始值设定项列表

    { {} }
    
    double类型的标量对象可以用空括号
    {}
    初始化


    结果,表达式创建了一个类型为
    MyItem
    的临时对象,该对象由初始值设定项列表初始化,该初始值设定项列表包含一个类型为double的元素,该元素的值通过空大括号初始化。

    您知道它是如何精确推断该类型的吗?{}是否扮演默认构造函数的角色?没有指定类型或
    auto
    。我对机械感兴趣,比如编译器推断它的步骤。@NikolayPolivanov,这可能是最棘手的上下文,在这种上下文中允许使用大括号。一般来说,当您重复类型并且编译器已经知道它时,它们是允许的。例如,您有
    voidfoo(string)
    。假设您希望传递“abcde”的前n个字符,其中n是一个变量。您通常会执行类似于foo(string(“abcde”,n))的操作。但是,它显然是一个字符串,那么为什么要重复该类型呢<代码>foo({“abcde”,n})使用
    {}
    时,通常是值初始化,通常为0或默认构造函数<代码>foo({})传递一个空字符串。即使如此,列表构造函数还是非常贪婪。例如,
    std::string
    有一个列表构造函数,它获取
    char
    的列表。如果你做了
    foo({5,'A'}),您可能希望得到一个包含五个a字符的字符串(AAAAA),因为有一个用于该字符串的构造函数。然而,即使5不是一个
    字符
    ,它仍然可以转换为一个,这意味着您实际得到的字符值为5(可能是一个控制字符),后跟一个a。这就是这些字符的贪婪程度。
    (const char*,size\t)
    调用之所以有效,是因为
    “abcde”
    不能转换为
    char
    知道用大括号制作
    字符串
    ——它只能是一种类型!同样,有一条规则说,
    MyItem foo{{}调用将从元素(这里仅是内部的
    {}
    )创建一个
    初始值设定项列表
    。还有一条规则说,要从
    {}
    中生成一个
    双精度的
    ,您得到的值是0.0。将这些元素放在一起,您可以看到可以创建一个
    初始值设定项列表
    -一个元素,其中
    {}
    被转换为0.0。谢谢。只需从1元素示例中取消单击,就可以使用3 double
    MyItem{{},{},{}}
    创建初始值设定项\u列表-这样它就可以从模板参数中知道类型
    MyItem{{}}
    
    MyItem(std::initializer_list<double> l) {
        std::cout << "l size " << l.size() << ")" << std::endl;
    }
    
    MyItem( {{}} );
    
    { {} }