让我们考虑以下几点:
#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}
被默默地打破了。 a
应该使用int
进行初始化。
我理解语言语法正在考虑将{10}
作为包含一个项目的列表。但是,我怎样才能防止旧代码的这种无声破坏?
-Wall -Wextra
。()
Foo b(20)
,用于其他构造函数,并且仅当我们真正意味着初始化程序时才使用{}
列表?答案 0 :(得分:5)
在这些情况下无法生成任何警告,因为在直接匹配中选择std::initializer_list
构造函数的行为已明确定义且符合标准。
Scott Meyers Effective Modern C++ book中详细介绍了此问题 第7项:
但是,如果一个或多个构造函数声明了一个类型的参数
std::initializer_list
,使用支持的初始化语法进行调用 非常喜欢使用std :: initializer_lists的重载。强烈。 如果编译器有任何方法可以使用支撑来解释一个呼叫 初始化器是一个构造函数,取std::initializer_list
, 编制者将采用这种解释。
他还提出了一些关于这个问题的边缘案例,我强烈建议你阅读它。
答案 1 :(得分:3)
我找不到这样的选项,所以显然在这种情况下你应该对具有initializer_list构造函数的类使用括号,并根据需要对所有其他类进行统一初始化。
可以在此答案中找到一些有用的见解并对其进行评论:https://stackoverflow.com/a/18224556/2968646
答案 2 :(得分:2)
没有编译器警告,也永远不会。警告代码执行像
这样的常见事情是没有意义的std::vector vec{1};
请记住,编译器只会警告真正不需要的东西,比如未定义的行为。它无法知道在上面的定义中,你的意思是调用构造函数来获取一个size参数。事实上,它知道你实际上想要拥有一个元素的向量!它无法读懂你的想法:)
你的第二个问题的答案基本上是肯定的。你总是可以添加一个虚拟参数,如struct {} dummy;
,以避免使用带有初始化列表的构造函数,但实际上,唯一相同的解决方案只是使用括号而不是括号(或者不要突然破坏界面)。
如果要更改使用列表初始化的代码的每个部分,可以删除初始化列表构造函数,将其更改为大括号,然后然后正确实现构造函数。我会认为这种改变是破坏性的,并适当地处理它。另一个想法是事先提出初始化列表用例,并立即实现它。