构造函数和initializer_list

Constructor and initializer_list

本文关键字:list initializer 构造函数      更新时间:2023-10-16

谁能告诉我这背后的理论?

为什么最后一个调用不能编译?

测试。cc:在函数' int main() '中:测试。Cc:15:12:错误:' int ' [-fpermissive]的初始化式周围有太多大括号

错误:从"到"的无效转换[-fpermissive]测试。Cc:9:6:错误:初始化' void f(std::initializer_list) '的参数1 [-fpermissive] test.cc:15:12:

错误:聚合值在期望的整数中使用

我认为c++11或c++ 4.7在这一点上是坏的。谢谢你!

#include <initializer_list>
class A { 
  public:
  A(const std::initializer_list<int>) {}
};
void f(const std::initializer_list<int>) {}
int main() {
  A({1});  // Compile OK
  f({1});  // Compile OK
  A({{{1}}});   // Compile OK
  //f({{{1}}}); // Compile Error.
}

我相信GCC是这么想的。

这是你的程序,有额外的一行,有趣的行编号。

int main() {
  A({1});  // 1. Compile OK
  f({1});  // 2. Compile OK
  A{{1}};  // 3. Compile OK, equivalent to 1. 
  A({{{1}}});   // 4. Compile OK
  //f({{{1}}}); // 5. Compile Error.
}

为什么GCC只编译4而不编译5?

为清楚起见,假设#4的结构实际上声明了一些东西:
A a{{{1}}};   // 4a. Compile OK

GCC询问构造函数{{1}}的参数是否为隐式转换为A。所以是:

A{{1}}

{{1}}A的有效转换?3.

这个推理当然不适用于#5;因此错误。

如果您想阻止GCC接受#4,那么阻塞通过显式地启用构造函数来启用转换:

class A { 
    public:
    explicit A(const std::initializer_list<int> il) {}
};

那么#4将给出错误:

error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’

A{1}可以初始化int类型。{{1}}可能不应该这样做——委员会对此有一个缺陷报告。GCC禁止这样做,而clang目前只是倾向于发出关于冗余大括号的警告。

当X是具有copy或move构造函数的类时,则X({…})可以调用其中一个构造函数。注意X{…}也可以,但限制为不允许用户定义转换(对于复制或移动构造函数)。

现在有了A({{{1}}}),第一个大括号被复制/移动构造函数所消耗。第二个递归到初始化列表。第三个是包含的int

根据标准,增加一个括号将打破A({{{{1}}}})。因为第二个大括号需要由a的复制/移动构造函数使用,但需要用户定义的转换序列。对于A{{{{1}}}}也是如此,因为这个原因它也是无效的。