David Ledger
David Ledger

Reputation: 2101

C++20 Designated Initializers char[]

C++20 introduces designated initialisers. I'm trying to initalise a character array inside a struct with the new syntax.

Pretty simple problem, I think code may explain it best:

struct Test
{
    unsigned v;
    char b[12];
};

int main()
{
    char str[12] = "hello"; // Works.
    char strb[12]{"hello"}; // Works.
    //
    Test testa
    {
        .v = 100u,
        .b = "hello" //Doesn't work...
    };
    Test testb
    {
        .v = 100u,
        .b = { "hello" } //Doesn't work...
    };
    Test testc
    {
        .v{ 100u },
        .b{ "hello" } //Doesn't work...
    };
    Test testd
    {
        .v{ 100u },
        .b{ "hello" } //Doesn't work...
    };
    Test teste
    {
        .v = 100u,
        .b = {} //This works.
    };
    Test testf
    {
        .v = 100u,
        .b = {'h', 'e', 'l', 'l', 'o', '\0'} //This works.
    };
    return 0;
}

I find this behaviour bazzar, the char str[12] = "hello"; line works just fine. But the same initaliation form doesn't work in designated initialiser lists.

Question : Why can't I initialize the char array with a string literal?

Edit

I was previously using GCC. This works with clang. Is there a workaround for GCC and, is clang or GCC correct?

Upvotes: 4

Views: 894

Answers (2)

Nicol Bolas
Nicol Bolas

Reputation: 473397

Designated initializers are a minor variation of aggregate initialization. The only use of the designator names are to decide which aggregate member to initialize from the given brace-or-equal initializer. The use of designated initialization changes nothing about the specific form of initialization and therefore, whether or not it is valid.

Given your Test object, Test{100u, "hello"} and Test{.v = 100u, .b = "hello"} are either both valid or both invalid. In both cases, Test::b is initialized in accord with [dcl.init.aggr]4.2:

Otherwise, the element is copy-initialized from the corresponding initializer-clause or is initialized with the brace-or-equal-initializer of the corresponding designated-initializer-clause.

Copy-initialization is the exact same process it would be if you simply initialized an array variable. Which is perfectly valid.

So your could should work. This is a compiler bug.

The GCC "workaround" is to wait for the bug to be fixed. Or go back to standard aggregate initialization until their compiler is fixed.

Upvotes: 2

Antares
Antares

Reputation: 671

I would say you can't initialise it this way because they are not type compatible. Well, if seen on a strict level... or "pedantic" level ;)

A char array is not equal to a std::string even if they are closely related. To be type safe, the compiler disallows such assignments.
Even char array and char* are not identical, as Geeks for Geeks explain.

I cannot see anything nonsensical here... may be there is something I overlooked?

The spec you posted states in the "Notes" section at the bottom:

In C, character array of size one less than the size of the string literal may be initialized from a string literal; the resulting array is not null-terminated. This is not allowed in C++.

I would argue that this explains it. But I agree, it is somewhat "hidden".

Upvotes: 0

Related Questions