有人可以告诉我这背后的理论吗?
为什么最后一次调用无法编译?
test.cc:在函数'int main()'中:test.cc:15:12:错误:'int'初始化器周围有太多括号[-fpermissive] test.cc:15:12:
错误:从''转换为'int'无效转换[-fpermissive] test.cc:9:6:错误:初始化'void f(std :: initializer_list)'[-fpermissive] test.cc的参数1: 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.
}
答案 0 :(得分:2)
以下是我认为GCC的想法。
这是你的程序,有1个额外的行,有趣的行编号。
int main() {
A({1}); // 1. Compile OK
f({1}); // 2. Compile OK
AA a{A
}; // 4a. Compile OK
; // 3. Compile OK, equivalent to 1.
A({AA
}); // 4. Compile OK
//f({class A {
public:
explicit A(const std::initializer_list<int> il) {}
};
}); // 5. Compile Error.
}
为什么GCC编译4而不是5?
为清楚起见,假设#4的构造实际上声明了一些东西:
error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’
GCC询问构造函数的参数是否为{{1}} 隐式可转换为{{1}}。所以是:
{{1}}
从{{1}}到{{1}}的有效转换?是的 - 按照3。
这种推理当然不适用于#5;因此错误。
如果你想阻止GCC接受#4,那么阻止 通过使启用构造函数显式启用转换:
{{1}}
然后#4将给出错误:
{{1}}
答案 1 :(得分:2)
{1}可以初始化int。一个{{1}}可能不应该 - 有一个关于委员会的缺陷报告。海湾合作委员会禁止这样做,并且铿锵声往往会发出有关多余支撑的警告。
当X是具有复制或移动构造函数的类时,X({...})可以调用它们中的一个。请注意,X {...}也可以,但仅限于不允许用户定义的转换(对于复制或移动构造函数)。
现在使用你的A({{{1}}}),第一个括号被复制/移动构造函数使用。第二个递归地转到初始化列表。第三个进入包含的int。
根据标准,添加一个大括号将打破A({{{{1}}}})。因为第二个大括号需要由A的复制/移动构造函数使用,但需要用户定义的转换序列。 A {{{{1}}}}同样适用,因此也无效。