Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无法从成员变量中的初始值设定项字符串推断数组大小的原因是什么?_C++_C++11_C Strings_In Class Initialization - Fatal编程技术网

C++ 无法从成员变量中的初始值设定项字符串推断数组大小的原因是什么?

C++ 无法从成员变量中的初始值设定项字符串推断数组大小的原因是什么?,c++,c++11,c-strings,in-class-initialization,C++,C++11,C Strings,In Class Initialization,以代码为例: struct Foo { const char str[] = "test"; }; int main() { Foo foo; } 它不能同时使用g++和clang++进行编译,从本质上讲,这是一个错误 错误:无法从类内初始值设定项推断数组绑定 我知道这可能是标准所说的,但有什么特别好的理由吗?由于我们有一个字符串文字,编译器似乎应该能够毫无问题地推断大小,类似于简单地声明类外constC类空终止字符串的情况。原因是,您始终可以重写构造函数中的类内初始值设定项

以代码为例:

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

int main()
{
    Foo foo;
}
它不能同时使用g++和clang++进行编译,从本质上讲,这是一个错误

错误:无法从类内初始值设定项推断数组绑定


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

原因是,您始终可以重写构造函数中的类内初始值设定项列表。所以我想最终,这可能会让人非常困惑

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
效果很好,这可能正是您想要的。

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

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

将导致未定义的行为。

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

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

  • 在非委托构造函数中,如果给定的非静态数据成员或 基类不是由mem初始值设定项id指定的(包括 没有mem初始值设定项列表的情况,因为构造函数 没有ctor初始值设定项),并且实体不是的虚拟基类 一个抽象类(10.4),然后

    • 如果实体是具有大括号或相等初始值设定项的非静态数据成员,则将按照中的指定初始化该实体 8.5;
    • 否则,如果实体是匿名联盟或变体成员(9.5),则不执行初始化
    • 否则,该实体将默认初始化
  • 12.6.2初始化基和成员[class.base.init]

  • 如果给定的非静态数据成员同时具有 大括号或相等的初始值设定项和mem初始值设定项,初始化 执行mem初始值设定项指定的,并且 忽略成员的大括号或相等初始值设定项。[示例:给定

    struct A { 
        int i = /∗ some integer expression with side effects ∗/ ; 
        A(int arg) : i(arg) { } 
        // ... 
    };
    
  • A(int)构造函数将简单地将i初始化为arg的值, i's brace或同等初始值设定项中的副作用不会发生 地点-结束示例]

    因此,如果存在非删除构造函数,则忽略大括号或等号初始值设定项,并以成员初始化中的构造函数为准。因此,对于省略了大小的数组成员,表达式的格式将变为病态。§12.6.2第9项使其更加明确,其中我们规定,如果由构造函数执行mem初始化,则省略r值初始值设定项表达式

    此外,谷歌集团的讨论,进一步阐述,使其更加清晰。它在解释大括号或等号初始值设定项是成员内初始化的一种美化方式时扩展了这一思想,这种方式适用于不存在成员内初始化的情况。例如

    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} {};
    }
    
    但是现在我们看到,如果忽略数组大小,表达式将是格式错误的


    但是接着说,编译器本可以在成员不是通过成员内构造函数初始化的情况下支持该功能,但目前为了统一起见,该标准与其他许多东西一样,不支持此功能。

    Related:由于
    str
    也可以在Foo构造函数的成员初始化列表中初始化,因此从类内初始化器中丢弃初始化器相关问题讨论:@aruistante谢谢,您可以将其标记为dupe,我自己无法找到dupe。虽然只有第一个链接可能是一个复制品,没有被接受的答案。@PiotrS。你应该发布一个答案,因为它现在清楚了!谢谢,有道理。在C++11之前,有没有办法使这项工作正常进行?仅使用
    static const
    不起作用。@有趣的是,这表明如果删除每个用户声明的构造函数,并且隐式生成默认构造函数,则可以允许这种行为。也许值得一提?