让我们考虑以下几点:
#include <iostream>
#include <initializer_list>
class Foo {
public:
Foo(int) {
std::cout << "with int\n";
}
};
int main() {
Foo a{10}; // new style initialization
Foo b(20); // old style initialization
}
运行时,它会打印:
with int
with int
一切都很好。现在,由于新的需求,我添加了一个接受初始化器列表的构造函数。
Foo(std::initializer_list<int>) {
std::cout << "with initializer list\n";
}
现在它会打印:
with initializer list
with int
因此,我的旧代码Foo a{10}
被悄悄地破坏了。应该使用int
初始化a
。
我知道语言语法认为{10}
是一个只有一项的列表。但是,我如何防止这种对旧代码的无声破坏呢?
-Wall -Wextra
.()
Foo b(20)
,并且只有在我们真正想要初始化器列表的时候才使用{}
?发布于 2017-09-25 22:13:28
在这些情况下不可能生成任何警告,因为选择std::initializer_list
构造函数而不是直接匹配的行为是定义良好的,并且符合标准。
此问题在 Item 7:中有详细描述
但是,如果一个或多个构造函数声明了
std::initializer_list
类型的参数,则使用带括号的初始化语法的调用强烈倾向于使用std::initializer_lists的重载。强烈地。如果有任何方法让编译器将使用带括号的初始化器的调用解释为接受std::initializer_list
的构造函数,编译器将采用这种解释。
他还提供了这个问题的一些边缘案例,我强烈建议您阅读它。
发布于 2017-09-25 14:10:53
我找不到这样的选项,所以很明显,在这种情况下,您应该对具有initializer_list构造函数的类使用括号,对所有其他类使用统一初始化。
在这个答案和评论中可以找到一些有用的见解:https://stackoverflow.com/a/18224556/2968646
发布于 2017-09-25 22:13:10
没有编译器警告,将来也不会有。警告代码做一些常见的事情是没有意义的,比如
std::vector vec{1};
请记住,编译器只对真正不需要的东西发出警告,比如未定义的行为。它没有办法知道在上面的定义中,你的意思是调用带大小参数的构造函数。因为它知道你实际上想要一个只有一个元素的向量!它无法读懂你的心思:)
你第二个问题的答案基本上是肯定的。您总是可以添加一个像struct {} dummy;
这样的伪参数来避免使用带有初始化器列表的构造函数,但实际上,唯一相同的解决方案就是使用圆括号而不是大括号(或者不要突然中断接口)。
如果要更改使用列表初始化的代码的每一部分,可以删除初始值设定项列表构造函数,将它们更改为大括号,然后正确实现该构造函数。我会认为这样的改变是一种破坏,并适当地处理它。另一个想法是事先拿出初始化器列表用例,并立即实现它。
https://stackoverflow.com/questions/46398411
复制相似问题