为了账号安全,请及时绑定邮箱和手机立即绑定

请问 为什么C+11类初始化器不能使用括号?

请问 为什么C+11类初始化器不能使用括号?

C++
繁星coding 2019-08-02 11:03:12
为什么C+11类初始化器不能使用括号?例如,我不能这样写:class A{     vector<int> v(12, 1);};我只能这样写:class A{     vector<int> v1{ 12, 1 };     vector<int> v2 = vector<int>(12, 1);};C+11语言设计的不同之处在于什么?
查看完整描述

2 回答

?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

这一选择背后的理由在相关的提案非静态数据成员初始化器 :

在科纳提出的关于识别资料范围的问题:

在2007年9月在科纳举行的核心工作组讨论期间,出现了一个关于初始化程序中标识符的范围的问题。我们想要允许类作用域与前向查找的可能性;还是我们想要求初始化程序在解析后被很好地定义?

想要什么:

类范围查找的动机是,我们希望能够将任何内容放入非静态数据成员的初始化器中,这样就可以在不显着改变语义的情况下将其放入mem初始化程序中(模块直接初始化与复制初始化):

int x();struct S {
    int i;
    S() : i(x()) {} // currently well-formed, uses S::x()
    // ...
    static int x();};struct T {
    int i = x(); // should use T::x(), ::x() would be a surprise
    // ...
    static int x();};

问题1:

不幸的是,在解析声明时,这使得“(表达式-列表)”形式的初始化器变得模糊不清:

   struct S {
        int i(x); // data member with initializer
        // ...
        static int x;
    };

    struct T {
        int i(x); // member function declaration
        // ...
        typedef int x;
    };

一个可能的解决方案是依赖现有的规则,如果声明可以是对象或函数,那么它就是一个函数:

 struct S {
        int i(j); // ill-formed...parsed as a member function,
                  // type j looked up but not found
        // ...
        static int j;
    };

类似的解决方案是应用另一条现有规则,目前仅在模板中使用,即如果T可以是类型或其他类型,那么它就是另一种类型;如果我们真正指的是类型,则可以使用“type Name”:

struct S {
        int i(x); // unabmiguously a data member
        int j(typename y); // unabmiguously a member function
    };

这两种解决方案都引入了许多可能被许多用户误解的微妙之处(如comp.lang.c+中关于为什么“intI();”at块作用域不声明默认初始化的int)的许多问题所证明的那样。

本文提出的解决方案是只允许“=初始化-子句”和“{初始化-列表}”形式的初始化程序。..,这解决了例如:

HashingFunction hash_algorithm{"MD5"};

在这里,我们不能使用=表单,因为HasningFunction的构造函数是显式的。在特别棘手的情况下,可能需要两次提到一个类型。考虑:

   vector<int> x = 3; // error:  the constructor taking an int is explicit
   vector<int> x(3);  // three elements default-initialized
   vector<int> x{3};  // one element with the value 3

在这种情况下,我们必须使用适当的表示法在这两种选择之间进行选择:

vector<int> x = vector<int>(3); // rather than vector<int> x(3);vector<int> x{3}; // one element with the value 3

问题2:

另一个问题是,由于我们不建议修改初始化静态数据成员的规则,添加静态关键字可能会使格式良好的初始化器不正确:

   struct S {
               const int i = f(); // well-formed with forward lookup
        static const int j = f(); // always ill-formed for statics
        // ...
        constexpr static int f() { return 0; }
    };

问题3:

第三个问题是类范围查找可能将编译时错误转换为运行时错误:

struct S {
    int i = j; // ill-formed without forward lookup, undefined behavior with
    int j = 3;};

(除非被编译器捕获,否则我可能会使用未定义的值j)。

建议:

CWG在科纳进行了6比3的民意调查,支持类范围查找;这也是本文所建议的,非静态数据成员的初始化器仅限于“=initiators-子句”和“{initiator-list}”表单。

我们认为:

问题1:这个问题不会发生,因为我们没有提出()表示法。=和{}初始化符号不受此问题的影响。

问题2:添加静态关键字会产生许多差异,这是其中最小的差异。

问题3:这不是一个新问题,而是与构造函数初始化器已经存在的初始化顺序相同的问题。




查看完整回答
反对 回复 2019-08-04
  • 2 回答
  • 0 关注
  • 331 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信