C++ 构造函数和初始值设定项\u列表

C++ 构造函数和初始值设定项\u列表,c++,c++11,g++,initializer-list,C++,C++11,G++,Initializer List,有人能告诉我这背后的理论吗 为什么最后一个调用无法编译 test.cc:在函数“int main()”中:test.cc:15:12:错误:“int”[-fpermissive]test的初始值设定项周围有太多大括号。cc:15:12: 错误:从“”到“int”[-fppermissive]测试的转换无效。cc:9:6:错误:初始化“void f(std::initializer_list)”[-fppermissive]测试的参数1。cc:15:12: 错误:在需要整数的位置使用了聚合值 我认

有人能告诉我这背后的理论吗

为什么最后一个调用无法编译

test.cc:在函数“int main()”中:test.cc:15:12:错误:“int”[-fpermissive]test的初始值设定项周围有太多大括号。cc:15:12:

错误:从“”到“int”[-fppermissive]测试的转换无效。cc:9:6:错误:初始化“void f(std::initializer_list)”[-fppermissive]测试的参数1。cc:15:12:

错误:在需要整数的位置使用了聚合值

我认为c++11或g++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.
}
#包括
A类{
公众:
(常数std::初始值设定项列表){}
};
void f(常数std::初始值设定项列表){}
int main(){
A({1});//编译正常
f({1});//编译正常
A({{{1}}});//编译正常
//f({{1}});//编译错误。
}

以下是我认为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) {}
};
A类{
公众:
显式A(const std::initializer_list il){}
};
然后#4将给出错误:

error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’
错误:从初始值设定项列表转换为“A”将使用显式构造函数“A::A(std::initializer_list)”

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

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

现在使用A({{{1}}}),复制/移动构造函数使用第一个大括号。第二个递归地转到初始值设定项列表。第三个是包含的int


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

谢谢。我说的是c++11.0中的标准头初始值设定项列表。在这两种情况下,Clang只是抛出了一个关于额外大括号的警告。我注意到f({1})和f({1}})都编译没有错误。他们之间有什么区别?我笨拙地描述了从
{{1}}
转换构造函数的过程,这在什么地方引起了轰动,但约翰尼斯得到了雪茄。我认为他的话“第二个递归地进入初始值设定项列表。”可能也解释了为什么
f({{1}})
是可以的。但我会听从他的。第一个括号是初始列表。第二个大括号表示int。