简体   繁体   中英

How does one partially initialize an array of C structs in C++?

I have a problem: with the following C++ code (which uses C-style structs), I get the following error:

elements of partially initialized array must have a default constructor

I assume that it's talking about not knowing how to implicitly initialize the rest of the elements of test.a , but I don't know how to fix it. Perhaps I need to simply add a constructor, but I don't want to have to change the struct definitions (this is only a stripped-down example of the actual problem that I'm facing).

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;
}

I don't care what comes after the elements that I manually initialized. I only care that I don't get the error.

Thank you for any help!

EDIT: If I add a default constructor to inner like so:

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

I then get more errors:

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

I've tried adding different constructors, but to no avail. What I don't understand is why C-style structs don't just have a default constructor.

Firstly, in C++11 this code should compile as is. (In C this code will also compile without any errors.) If you get this error, you must be using a pre-C++11 C++ compiler.

Now, regarding your declarations: it would be interesting to know why you declared inner::b as const . Why is inner::b declared const , but not inner::a or inner::c ? What is so special about inner::b ?

The same question can be asked about outer::a . Why did you decide to apply const directly to the specific member outer::a instead of declaring the entire outer object as const ?

If that was not intentional, then you can stop declaring individual struct members as const and just declare the whole test object as const instead:

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;
}

That will compile in a pre-C++11 compiler.

But if for some good reason it was intentional, meaning that you don't want to change your declarations, and you want to keep the types involved as C-style aggregates (ie no user-declared constructors), then your options are limited to supplying all initializers for all data fields individually declared as const .

PS The wording in the pre-C++11 language spec that makes the original code illegal and makes my version legal can be considered ambiguous and/or defective. This is probably the reason GCC accepts the original code even in -std=c++98 mode, but MSVC++ rejects it.

If you want to use aggregate initialization (which is what you are doing), you can't have any user defined constructors. It has to look like plain-old C. See initializer_list not working in VC10

If you remove the word const in front of const int b , then it compiles ok (I tried it in VS2008).

I think what you are trying to do is impossible, since declaring const int b as a member of a struct is a C++ concept that requires you to initialize b in a constructor, but you are not allowed to have any constructors if you are using an aggragate initializer.

First, I'd like to mention that all you probably need to do is add a default constructor for 'inner'. You've mentioned that you don't want to change the struct definitions, but I think that you'd have to. I have, however, listed an alternative.

Your problem:

The 'outer' type contains an array of fixed size 10, so when the variable "test" is initialised, it attempts to create 10 'inner's with the data given to it. Seeing as you aren't giving it enough, it attempts to create them anyway, but you don't have a default constructor for your 'inner' type so it doesn't know what to do.

Solutions:

1) (Simplest) Create a default constructor for 'inner'.

2) Make the "a" array in 'outer' a dynamic one, either using pointers or a class like std::vector (c++) / some other c class.

Hope that helps.

You don't need to change const variable to non-const, cause const variable can be initialized once. The original code is compiled successfully in my compiler(gcc 4.6.3) with g++. And also it is compiled successfully in Visual C++, but change the file extension to *.c.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM