代码之家  ›  专栏  ›  技术社区  ›  xdavidliu

C++标准中是否有任何计划来解决初始值设定项列表构造函数的不一致性?

  •  11
  • xdavidliu  · 技术社区  · 6 年前

    C++中的初始值设定项列表构造函数经常引起麻烦;例如

    using std::vector;
    using std::string;
    vector<string> v{3}; // vector of three empty strings
    vector<int> u{3}; // vector of one element with value 3
    

    (我只是想澄清一下 <int> 构造函数是初始值设定项列表构造函数,而 <string> 一个是 .)

    这个 int 大小写匹配初始值设定项列表构造函数,而 string 情况并非如此。这有点难看,常常会引起麻烦。ScottMeyers的《有效的现代C++》的早期章节(第7项)中也提到了这一点,他将其描述为标准中有点令人不快的一部分,即每当有初始值设定项列表构造函数可用时,编译器都会跳转尝试匹配它,使其优先于其他所有构造函数。

    当然,可以通过更改 u{3} u(3) ,但这不是重点。

    这是可取的行为吗?C++标准委员会是否有任何讨论或计划来解决这种模糊性/不愉快性?一个示例是要求像这样调用初始值设定项列表构造函数: vector<int> u({3}) ,目前已合法。

    2 回复  |  直到 6 年前
        1
  •  4
  •   Barry    6 年前

    C++标准委员会是否有任何讨论或计划来解决这种模糊性/不愉快性?

    自C++11以来,对初始化进行了许多修复。例如,最初无法使用列表初始化复制构造聚合( CWG 1467 ). 这个非常小的修复以一种不受欢迎的方式破坏了一些代码,从而导致了一个新问题,即如果存在 initializer_list 建造师( CWG 2137 ). 即使是在很小的情况下,如果没有许多意外的后果和破坏代码,很难触及这些条款中的任何内容。我怀疑会有人推动 大的 以后更改为初始化。此时,代码破坏的数量将是巨大的。

    最好的解决方案就是了解初始化的陷阱,并小心您正在做的事情。我的经验法则是 {} 当我故意需要 {} 提供,以及 () 否则

    请注意,这与以下更广为人知的陷阱并没有什么不同:

    vector<int> a{10}; // vector of 1 element
    vector<int> b(10); // vector of 10 elements
    

    一个示例是要求像这样调用初始值设定项列表构造函数: vector<int> u({3}) ,目前已合法。

    您有与之前相同的问题,原因相同:

    vector<int> u({3});    // vector of one element: 3
    vector<string> v({3}); // vector of three elements: "", "", and ""
    

    即使你要求前者(这是不可能的),你也不能使后者格式错误。

        2
  •  -7
  •   Swift - Friday Pie    6 年前

    首先是一个统一的初始值设定项,它被引入到 解决 语言的歧义。问题被称为 最烦人的解析 关于声明变量,用“round”()括号初始化。MVP是代码中的一种歧义解决方法,类似于以下内容:

    class  SomeInitClass;
    
    
    void  bleh()
    {
           int foo(SomeInitClass());
    }
    

    foo 这里实际上是一个函数的原型,该函数将返回一个条的函数作为其参数 foo公司 函数的返回值是 int . 基本上如果 某物 看起来像原型,C++就是这样处理的。

    int foo{SomeInitClass{}};
    

    SomeInitClass{} 将始终创建临时。 int foo{...} 总是会创建一个变量。

    虽然这两条线的工作方式不同:

    vector<string> v{3}; // vector of three empty strings
    vector<int> u{3}; // vector of one element with value 3
    

    他们 语义相同,它们是变量的声明。这种工作方式(以及您可以声明以初始值设定项列表为参数的构造函数)在C++语言中具有很大的意义,因为C++语言采用了隐藏语法背后的真实值和操作量的概念。

    这不是矛盾,至少不是主要矛盾。 vector<string> vector<int> 不是同一个类,也没有相同的构造函数,因为它们不是模板std::vector的相同实例化。为了避免混淆,可以使用别名并使用略有不同的语法。

     StringCollecton v{3}; //three strings;
     IntCollection   u = {3}; // or {{3}}
    

    当然 StringCollecton test = {3}; 在这种情况下不起作用,因为 3 不是可以转换为正确存储类型的文本。

    因为在声明中只能有一个初始值设定项,所以创建的字符串容器的设置值看起来是这样的:

    std::vector<std::string> test{3, {"string"}}; // all values initialized by "string"
    
    std::vector<std::string> test{{"string1","",""}}; // constructor introduced in C++11
    

    虽然我可能很懒惰,并且忽略了最里面的大括号,但语法are-the-syntax-sugar允许我显示其中是initializer\u列表。