C++ 添加初始值设定项\u列表构造函数后,构造函数调用的静默中断 我们考虑如下: #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 }

C++ 添加初始值设定项\u列表构造函数后,构造函数调用的静默中断 我们考虑如下: #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 },c++,c++11,initializer-list,C++,C++11,Initializer List,一切都好。现在,由于新的需求,我添加了一个构造函数,它采用初始值设定项列表 Foo(std::initializer_list<int>) { std::cout << "with initializer list\n"; } 因此,我的旧代码fooa{10}被悄悄地破坏了a应该用int初始化 据我所知,语言语法将{10}视为一个包含一项的列表。但我怎样才能防止这种对旧代码的无声破坏呢 是否有任何编译器选项会在此类情况下向我们发出警告?因为这将是特定于编译器的,

一切都好。现在,由于新的需求,我添加了一个构造函数,它采用初始值设定项列表

Foo(std::initializer_list<int>) {
    std::cout << "with initializer list\n";
}
因此,我的旧代码
fooa{10}
被悄悄地破坏了
a
应该用
int
初始化

据我所知,语言语法将
{10}
视为一个包含一项的列表。但我怎样才能防止这种对旧代码的无声破坏呢

  • 是否有任何编译器选项会在此类情况下向我们发出警告?因为这将是特定于编译器的,所以我主要对gcc感兴趣。我已经试过
    -Wall-Wextra
  • 如果没有这样的选项,那么我们是否总是需要对其他构造函数使用旧式构造,即使用
    ()
    foob(20)
    ,并且仅当我们真正想要初始值设定项列表时才使用
    {}

  • 我找不到这样的选项,所以显然在这种情况下,您应该对具有初始值设定项\u list构造函数的类使用括号,并根据需要对所有其他类进行统一初始化


    在这个答案和注释中可以找到一些有用的见解:

    没有编译器警告,也永远不会有。警告代码做一些常见的事情是没有意义的,比如

    std::vector vec{1};
    
    请记住,编译器只警告真正不需要的东西,如未定义的行为。它无法知道在上面的定义中,您的意思是使用size参数调用构造函数。据它所知,你实际上想要一个有一个元素的向量!它无法读懂你的心思:)

    第二个问题的答案基本上是肯定的。您始终可以添加一个伪参数,如
    struct{}dummy
    避免将构造函数与初始值设定项列表一起使用,但实际上,唯一相同的解决方案是使用括号而不是大括号(或者不要突然中断接口)


    如果要更改使用列表初始化的代码的每一部分,可以删除初始值设定项列表构造函数,将其更改为大括号,然后正确实现该构造函数。我会考虑这样的改变,一个适当的处理。另一个想法是提前提出初始化列表用例,并立即实施。

    在这些情况下不可能生成任何警告,因为在直接匹配上选择
    std::initializer\u list
    构造函数的行为定义良好,符合标准。

    有关此问题的详细说明,请参见 第7项:

    但是,如果一个或多个构造函数声明类型为的参数
    std::initializer\u list
    ,使用括号内的初始化语法调用 强烈喜欢使用std::initializer\u列表的重载。强烈地。 如果编译器有任何方法可以使用大括号分析调用 初始值设定项是一个采用
    std::initializer\u列表的构造函数
    , 编撰者将采用这种解释


    他还介绍了这个问题的一些边缘案例,我强烈建议您阅读。

    为什么投票被否决?它措辞得体,可能对未来的读者有用。严肃地说,人们,否决投票是为了反映帖子质量,而不是你有多喜欢或不喜欢这个话题。答案是(2),在你展示的例子中,没有理由用大括号代替括号。正如
    vector
    所展示的,向现有接口添加一个
    初始值设定项\u list
    构造函数是不可取的,除非其好处显著。旧代码没有这个问题,列表初始化是C++11的一个特性,这也是为什么标准库从来没有problems@PasserBy-正如他们所说,事后诸葛亮是20/20。说“史崔的结束”真是太傲慢了。代码库随着需求的变化和发展而变化。你不可能永远证明自己的未来。如果这听起来像是自高自大,我很抱歉,这正是我此刻在想的。我应该选择更仔细的词,就像你链接的答案描述了我所问的确切情况一样。而且似乎没有太多其他的选择来阻止它。
    with initializer list
    with int
    
    std::vector vec{1};