无法从成员变量中的initializer-string中推断出数组大小的原因是什么?

时间:2015-04-12 18:45:26

标签: c++ c++11 c-strings in-class-initialization

考虑代码:

struct Foo
{
    const char str[] = "test";
};

int main()
{
    Foo foo;
}

无法使用g ++和clang ++编译,基本上是吐出

  
    

error: array bound cannot be deduced from an in-class initializer

  

我明白这是标准可能会说的,但有什么特别好的理由吗?由于我们有一个字符串文字,似乎编译器应该能够毫无问题地推断出大小,类似于你只是声明一个类外的const C类空终止字符串。

3 个答案:

答案 0 :(得分:11)

原因是您始终可以覆盖构造函数中的类内初始化列表。所以我想这最终会让人感到困惑。

struct Foo
{
   Foo() {} // str = "test\0";

   // Implementing this is easier if I can clearly see how big `str` is, 
   Foo() : str({'a','b', 'c', 'd'}) {} // str = "abcd0"
   const char str[] = "test";
};

请注意,将const char替换为static constexpr char非常有效,而且可能是您想要的。

答案 1 :(得分:2)

如果允许编译器支持您描述的内容,并且str的大小推断为5

Foo foo = {{"This is not a test"}};

会导致未定义的行为。

答案 2 :(得分:2)

正如评论中所提到的以及@sbabbi的回答,答案在于细节

12.6.2初始化基础和成员[class.base.init]

  
      
  1. 在非委托构造函数中,如果给定的非静态数据成员或   基类不是由mem-initializer-id指定的(包括   因为构造函数没有mem-initializer-list的情况   没有ctor-initializer)并且实体不是虚拟基类   抽象类(10.4),然后

         
        
    • 如果实体是具有大括号或等于初始化程序的非静态数据成员,则实体初始化为   8.5;
    •   
    • 否则,如果实体是匿名联合或变体成员(9.5),则不执行初始化;
    •   
    • 否则,实体默认初始化
    •   
  2.   

12.6.2初始化基础和成员[class.base.init]

  
      
  1. 如果给定的非静态数据成员同时具有   brace-or-equal-initializer和mem-initializer,初始化   由mem-initializer指定执行,以及非静态数据   member的brace-or-equal-initializer被忽略。 [例子:给定

    struct A { 
        int i = /∗ some integer expression with side effects ∗/ ; 
        A(int arg) : i(arg) { } 
        // ... 
    };
    
  2.         

    A(int)构造函数只需将i初始化为arg的值,   并且i的括号或等于初始化器的副作用不会   地点。 - 结束例子]

因此,如果存在非删除构造函数,则忽略brace-or-equal-initializer,并且构造函数in-member初始化占优势。因此,对于省略了大小的阵列成员,表达式变得不正确。 §12.6.2,第9项,使得它更明确,我们指定如果构造函数执行mem初始化,则省略r值初始值设定项表达式。

此外,谷歌小组讨论Yet another inconsitent behavior in C++,进一步阐述并使其更清晰。它扩展了这个想法,解释了对于成员的成员内初始化不存在的情况,大括号初始化器是一种成员初始化的美化方式。作为一个例子

struct Foo {
    int i[5] ={1,2,3,4,5};
    int j;
    Foo(): j(0) {};
}

相当于

struct Foo {
    int i[5];
    int j;
    Foo(): j(0), i{1,2,3,4,5} {};
}

但是现在我们看到如果省略了数组大小,那么表达式将是错误的。

但后来说,编译器可能支持该功能,当成员未通过成员构造函数初始化初始化但目前为了统一,标准像许多其他东西一样,不支持此功能。