【问题标题】:How does one partially initialize an array of C structs in C++?如何在 C++ 中部分初始化一组 C 结构?
【发布时间】:2013-07-09 21:05:50
【问题描述】:

我有一个问题:使用以下 C++ 代码(使用 C 风格的结构),我收到以下错误:

elements of partially initialized array must have a default constructor

我假设它在谈论不知道如何隐式初始化test.a 的其余元素,但我不知道如何解决它。也许我需要简单地添加一个构造函数,但我不想更改结构定义(这只是我面临的实际问题的一个精简示例)。

typedef struct inner_t
{
    const char* a;
    const int b;
    const char* c[6];
} inner;

typedef struct outer_t
{
    const inner a[10];
} outer;

int main()
{
    outer test = {{
        { "hi!", 0, { "1", "2", "3", "4", "5", ""} },
        { "", -1, { "" } }
    }};

    return 0;
}

我不在乎我手动初始化的元素之后会发生什么。我只关心我没有收到错误。

感谢您的帮助!

编辑:如果我像这样向inner 添加默认构造函数:

typedef struct inner_t
{
    /* previous stuff */
    inner_t() : a(""), b(-1) { }
}

然后我得到更多错误:

initialization with '{...}' is not allowed for object of type "const inner"

我尝试添加不同的构造函数,但无济于事。我不明白为什么 C 风格的结构不只是一个默认构造函数。

【问题讨论】:

  • 这符合g++和clang,你的编译器是什么?
  • 我在 MS VS 2010 Premium 中编译它。
  • 只需将inner(){} 添加到内部结构中?你在用 c 代码共享这个代码吗?
  • 所有这些成员变量(如const int b)真的需要为常量吗?显然 VC++ 不喜欢那样。
  • 备注:在struct inner_t 中,虽然bconst,但ac 不是故意的吗? (他们将在* 之后添加const

标签: c++ c initializer-list


【解决方案1】:

首先,在 C++11 中,这段代码应该按原样编译。 (在 C 中,此代码也将无任何错误地编译。)如果您收到此错误,则必须使用 C++11 之前的 C++ 编译器。

现在,关于你的声明:知道你为什么将inner::b 声明为const 会很有趣。为什么inner::b 声明为const,而不是inner::ainner::cinner::b 有什么特别之处?

对于outer::a,可以提出同样的问题。为什么决定将const 直接应用于特定成员outer::a,而不是将整个outer 对象声明为const

如果这不是故意的,那么您可以停止将单个结构成员声明为 const,而只需将整个 test 对象声明为 const

typedef struct inner_t
{
    const char* a;
    int b;                       // <- removed `const` here
    const char* c[6];
} inner;

typedef struct outer_t
{
    inner a[10];                 // <- removed `const` here
} outer;

int main()
{
    const outer test = {{        // <- added `const` here
        { "hi!", 0, { "1", "2", "3", "4", "5", ""} },
        { "", -1, { "" } }
    }};

    return 0;
}

这将在 C++11 之前的编译器中编译。

但如果出于某种充分的理由这是故意的,这意味着您不想更改声明,并且您希望将所涉及的类型保留为 C 风格的聚合(即没有用户声明的构造函数),那么您的选择仅限于为单独声明为 const 的所有数据字段提供所有初始化程序。

附: C++11 之前的语言规范中使原始代码非法并使我的版本合法的措辞可以被认为是模棱两可和/或有缺陷的。这可能是 GCC 即使在 -std=c++98 模式下也接受原始代码但 MSVC++ 拒绝它的原因。

【讨论】:

  • 感谢您的回答!我会尝试你告诉我的改变,但不幸的是它必须等到星期一,因为代码正在工作。如果它有效,那么我会将其标记为答案。
【解决方案2】:

如果你想使用聚合初始化(这就是你正在做的),你不能有任何用户定义的构造函数。它必须看起来像普通的 C。见 initializer_list not working in VC10

如果你把const int b前面的const这个词去掉,那么它就可以编译了(我在VS2008中试过)。

我认为你试图做的事情是不可能的,因为将const int b 声明为结构的成员是一个 C++ 概念,它要求你在构造函数中初始化 b,但如果你这样做,则不允许有任何构造函数正在使用聚合初始化器。

【讨论】:

  • 将成员声明为const 不需要通过构造函数进行初始化。聚合初始化也将起作用。但是每个const 成员都需要有自己的显式聚合初始值设定项。 OP 的代码无法编译,因为并非所有 innner::bs 都有自己的聚合初始值设定项。
  • @AndreyT 你是对的。我的意思是声明const b 要求您在构造时初始化值b——通过显式构造函数或显式初始化程序。
【解决方案3】:

首先,我想提一下,您可能需要做的就是为“inner”添加一个默认构造函数。您已经提到您不想更改结构定义,但我认为您必须这样做。但是,我列出了一个替代方案。

你的问题:

'outer' 类型包含一个固定大小为 10 的数组,因此当变量“test”初始化时,它会尝试使用给定的数据创建 10 个 'inner'。鉴于您提供的不够多,它无论如何都会尝试创建它们,但是您没有“内部”类型的默认构造函数,因此它不知道该怎么做。

解决方案:

1)(最简单)为'inner'创建一个默认构造函数。

2) 使用指针或像 std::vector (c++) / 其他 c 类这样的类使“外部”中的“a”数组成为动态数组。

希望对您有所帮助。

【讨论】:

  • 感谢您的回答,但我已经尝试为inner 创建一个默认构造函数,我无法将其更改为动态。我编辑了我的问题以反映构造函数的添加。
  • 这个答案其实是不正确的。提供默认构造函数将禁用任何聚合初始化;这似乎是重点。
【解决方案4】:

您不需要将 const 变量更改为 non-const,因为 const 变量可以初始化一次。原始代码在我的编译器(gcc 4.6.3)中使用 g++ 成功编译。并且在Visual C++中编译成功,但是将文件扩展名更改为*.c。

【讨论】:

    猜你喜欢
    • 2016-09-29
    • 2021-08-02
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    相关资源
    最近更新 更多