non-trivial designated initializers not supported
Asked Answered
F

7

86

I have a structure as follows:

struct app_data
{
    int port;
    int ib_port;
    unsigned size;
    int tx_depth;
    int sockfd;
    char *servername;
    struct ib_connection local_connection;
    struct ib_connection *remote_connection;
    struct ibv_device *ib_dev;

};

When I try to initialize it thus:

struct app_data data =
{
    .port = 18515,
    .ib_port = 1,
    .size = 65536,
    .tx_depth = 100,
    .sockfd = -1,
    .servername = NULL,
    .remote_connection = NULL,
    .ib_dev = NULL
};

I get this error:

sorry, unimplemented: non-trivial designated initializers not supported

I think it wants the order of initialization exactly as it is declared, and local_connection is missing. I don't need to initialize it though, and setting it to NULL doesn't work.

If I change it to this for g++, still get the same error:

struct app_data data =
{
    port : 18515,
    ib_port : 1,
    size : 65536,
    tx_depth : 100,
    sockfd : -1,
    servername : NULL,
    remote_connection : NULL,
    ib_dev : NULL
};
Felty answered 4/7, 2015 at 1:27 Comment(9)
I think you are using g++ to compile this code. If yes, remove the "." i.e. .port becomes port, .ib_port becomes ib_port. It should compile after that.Coenzyme
I am using g++ 4.9.2 (with c++11 enabled), but removing the . does not work? "port was not declared in this scope"Felty
Oh. Forgot to mention, use ":" instead of "=" e.g. port: 18515 and do this for other variables too.Coenzyme
Ok, the colon seems to pass the compiler, but it still complains with the same error. I think I have to have ALL fields initialized in the exact order. But there is a struct inside the struct, "local_connection", not a struct pointer? In plain C it works. In C++ I get this error.Felty
The error is the title of this thread. Also in the body of the post.Felty
I showed you how to initialized the ib_connection struct. Note that order matters. Tested on g++. Was able to compile and link.Coenzyme
@Felty make sure the order of fields in the constructor matches the order of fields in the struct declarationEaldorman
I think you are missing field local_connection in the assigment?Jacobus
This question is a manifest of how broken and unaligned the C and C++ standards are still in 2018.Diazo
C
34

This does not work with g++. You are essentially using C constructs with C++. Couple of ways to get around it.

1) Remove the "." and change "=" to ":" when initializing.

#include <iostream>

using namespace std;
struct ib_connection
   {
    int x;
   };

   struct ibv_device
   {
   int y;
  };

struct app_data
{
    int port;
    int ib_port;
    unsigned size;
    int tx_depth;
    int sockfd;
    char *servername;
    struct ib_connection local_connection;
    struct ib_connection *remote_connection;
    struct ibv_device *ib_dev;

};

int main()
{

    struct app_data data =
    {
        port : 18515,
        ib_port : 1,
        size : 65536,
        tx_depth : 100,
        sockfd : -1,
        servername : NULL,

        local_connection : {5},
        remote_connection : NULL,
        ib_dev : NULL
    };

   cout << "Hello World" << endl; 

   return 0;
}

2) Use g++ -X c. (Not recommended) or put this code in extern C [Disclaimer, I have not tested this]

Coenzyme answered 4/7, 2015 at 1:56 Comment(13)
Also note this code is not portable (but will work with g++). What is the reason you are using C constructs with C++? Doing some kernel/driver implementation?Coenzyme
Thanks that works. BTW, the dots work in C++. Not sure why you suggested ":" instead. As to usage of C, it is mostly that I have examples that are in C and I am trying to port it to C++. One thing at a time.Felty
@Felty Thanks, +1 for you. I did not know that. Tried ".port = 6000" and it worked!Coenzyme
extern "C" does not change the language, just the linkage. I.e. it tells the C++ compiler to compile C++ code such that it can be linked with cod from a C compiler.Sonyasoo
As @Sonyasoo said, I get the same error even if in extern "C".Csc
@BeeOnRope, did the first method work for you? If not, can you paste your code? I can take a look.Coenzyme
@Coenzyme - yes, the first method probably works, but I needed code which worked in both C and C++ in my case. I worked around it by moving the initializer out of the header.Csc
This was not the correct answer for me with g++. Instead, the solution turned out to be missing and out-of-order fields in the initializer. It seems that both gcc and clang are more lenient, and it's just g++ that has this limitation.Impaste
Here are the docs about the aggregate initialization in C++, it clearly shows the .<field name> = <expr> as one of the possible ways to initialize your structures (since C++20, though...)Jansenism
It's kinda weird but this answer didn't work for me. but @parallel-universe answer worksGigantic
@BehnamGhiaseddin This answer doesn't work for me either. When I change .member = initval to member : initval, g++ 4.9.2 emits the same error: non-trivial designated initializers not supported. It looks like the two are just syntactic sugars for the same underlying mechanism, which is not complete in that compiler.Hamnet
This is non-standard and actually a GNU extension. Clang kind of accept it but issue a diagnosis saying "use of GNU old-style field designator extension". This answer is the new standard-conformant way to do it in C++20.Gemmulation
Not work with g++5.4.Why? @CoenzymeAlodi
H
112

the order of initialization needs to be in the exact order of declaration.

typedef struct FOO
{
    int a;
    int b;
    int c;
}FOO;

FOO foo   = {.a = 1, .b = 2}; // OK
FOO foo1  = {.a = 1};         // OK
FOO foo2  = {.b = 2, .a = 1}; // Error sorry, unimplemented: non-trivial designated initializers not supported
FOO foo3  = {.a = 1, .c = 2}; // Error sorry, unimplemented: non-trivial designated initializers not supported

I understand that this means that the compiler has no support for name-oriented, out-of-order, member initialization.

Need to initialize the struct in the old fashioned way. I keep the variable names for clarity, but I have to initialize them in order, and not skip a variable.

I can stop the initialization at any variable, but can't initialize variables that come of that.

Historicity answered 6/9, 2017 at 5:16 Comment(2)
Contrary to the accepted answer's statement that this doesn't work in g++, I am successfully using g++ (5.3.0) with the solution given in this answer (and not using "-X").Welborn
This answer worked for me. I could initialize by field name, but it had to be in the order that I declared them.Hesse
C
34

This does not work with g++. You are essentially using C constructs with C++. Couple of ways to get around it.

1) Remove the "." and change "=" to ":" when initializing.

#include <iostream>

using namespace std;
struct ib_connection
   {
    int x;
   };

   struct ibv_device
   {
   int y;
  };

struct app_data
{
    int port;
    int ib_port;
    unsigned size;
    int tx_depth;
    int sockfd;
    char *servername;
    struct ib_connection local_connection;
    struct ib_connection *remote_connection;
    struct ibv_device *ib_dev;

};

int main()
{

    struct app_data data =
    {
        port : 18515,
        ib_port : 1,
        size : 65536,
        tx_depth : 100,
        sockfd : -1,
        servername : NULL,

        local_connection : {5},
        remote_connection : NULL,
        ib_dev : NULL
    };

   cout << "Hello World" << endl; 

   return 0;
}

2) Use g++ -X c. (Not recommended) or put this code in extern C [Disclaimer, I have not tested this]

Coenzyme answered 4/7, 2015 at 1:56 Comment(13)
Also note this code is not portable (but will work with g++). What is the reason you are using C constructs with C++? Doing some kernel/driver implementation?Coenzyme
Thanks that works. BTW, the dots work in C++. Not sure why you suggested ":" instead. As to usage of C, it is mostly that I have examples that are in C and I am trying to port it to C++. One thing at a time.Felty
@Felty Thanks, +1 for you. I did not know that. Tried ".port = 6000" and it worked!Coenzyme
extern "C" does not change the language, just the linkage. I.e. it tells the C++ compiler to compile C++ code such that it can be linked with cod from a C compiler.Sonyasoo
As @Sonyasoo said, I get the same error even if in extern "C".Csc
@BeeOnRope, did the first method work for you? If not, can you paste your code? I can take a look.Coenzyme
@Coenzyme - yes, the first method probably works, but I needed code which worked in both C and C++ in my case. I worked around it by moving the initializer out of the header.Csc
This was not the correct answer for me with g++. Instead, the solution turned out to be missing and out-of-order fields in the initializer. It seems that both gcc and clang are more lenient, and it's just g++ that has this limitation.Impaste
Here are the docs about the aggregate initialization in C++, it clearly shows the .<field name> = <expr> as one of the possible ways to initialize your structures (since C++20, though...)Jansenism
It's kinda weird but this answer didn't work for me. but @parallel-universe answer worksGigantic
@BehnamGhiaseddin This answer doesn't work for me either. When I change .member = initval to member : initval, g++ 4.9.2 emits the same error: non-trivial designated initializers not supported. It looks like the two are just syntactic sugars for the same underlying mechanism, which is not complete in that compiler.Hamnet
This is non-standard and actually a GNU extension. Clang kind of accept it but issue a diagnosis saying "use of GNU old-style field designator extension". This answer is the new standard-conformant way to do it in C++20.Gemmulation
Not work with g++5.4.Why? @CoenzymeAlodi
J
16

I have noticed my GCC compiler has some trick to accept .fieldname=value assigments but will only compile if fields come in the same order they are declared in the struct.

I was able to init this struct in two ways. The one with names improves readability and reduces the risk of assigning the wrong data if the struct field order is later changed.

//Declare struct
typedef struct
{
    uint32_t const * p_start_addr;
    uint32_t const * p_end_addr;
    fs_cb_t  const   callback;    
    uint8_t  const   num_pages;  
    uint8_t  const   priority;
} fs_config_t;

//Assign unnamed
fs_config_t fs_config  
{
    (uint32_t*)0x00030000,  // uint32_t const * p_start_addr;
    (uint32_t*)0x00038000,  // uint32_t const * p_end_addr;         
    fs_evt_handler,         // fs_cb_t  const   callback;
    8,                      // uint8_t  const   num_pages;
    0xFE                    // uint8_t  const   priority;               
};

//Assign to named fields
static fs_config_t fs_config1  
{
    .p_start_addr = (uint32_t*)0x00030000,
    .p_end_addr = (uint32_t*)0x00038000,            
    .callback = fs_evt_handler,
    .num_pages = 8,
    .priority = 0xFE                
};      

The rule of thumb is:

  1. Assign to .name=value fields
  2. Assign in the order they where declared
  3. Include all fields in the assigment
Jacobus answered 29/7, 2017 at 9:32 Comment(2)
All fields are not required, but they have to be in order. Missing fields will be set to zero or their default value (i.e. if you have struct T { int a; int b = 3 }; T t = { .a = 55 }; then b is set to 3 (since C++11.) In C++20, the order and whether fields are missing will not matter.Jansenism
I had this issue with g++ / C++14 but all I had were missing fields (none out of order). I had to add the missing fields (assigning them to something) to get past the compiler error.Tubate
H
7

Since none of the other approaches worked for me with the Arduino IDE, I decided to simply set each field separately:

struct app_data data;

data.port = 18515;
data.ib_port = 1;
data.size = 65536;
data.tx_depth = 100;
data.sockfd = -1;
data.servername = NULL;
data.remote_connection = NULL;
data.ib_dev = NULL;
Horripilate answered 16/3, 2018 at 10:1 Comment(2)
Which version of g++ was that? 3.x? 4.x?Jansenism
I just accomplished initializing a struct in Arduino IDE (1.8.12). I literally copied the typedef from the .h file to my code and initialized it. Order and number of members must match.Undress
D
5

Unfortunately, C++ doesn't support designated initialisers. GCC still lets you use them (as an extension) but you must initialise members in the same order as they are listed in the struct.

Another workaround is to use an immediately invoked lambda:

constexpr fuse_operations fuse_ops = []{
  fuse_operations ops{};
  ops.destroy = wiifs_destroy;
  ops.getattr = wiifs_getattr;
  ops.access = wiifs_access;
  // ...
  return ops;
}();

I personally prefer this solution because it is perfectly standard C++, it lets you initialise fields in the order you want, skip the ones you don't need and default initialise the rest. And the compiler is still able to optimise this. Do note that this will only work with C++17 or newer.

Denis answered 17/2, 2018 at 13:5 Comment(2)
For me it compiled using C++11, g++ 4.8.4, just with static instead of constexprCimabue
@OrenKishon the point of this is that it is evaluated at compile time, which might not happen if fuse_ops is declared static (instead then it would be left up to optimizations by the compiler).Winsor
P
3

I was hit by a variant of this. Consider this broken code:

enum {
    S_START,
    S_ANOTHER,
    S_LAST
} STATES;

const char* STATE_NAMES[] = {
    [S_START] = "S_START",
    [S_LAST] = "S_LAST",
};

int main() {
}

Here's the error message:

a.cpp:10:1: sorry, unimplemented: non-trivial designated initializers not supported
   10 | };

The problem was that I forgot to define S_ANOTHER entry in STATE_NAMES.

Perch answered 15/4, 2022 at 17:40 Comment(0)
C
-1

Also note that, as the original question stated, the order of the member expressions matter. I noticed that if I would like to only initialize "size" in the previous example, I need to put expressions for .port and .ib_port before. Otherwise I get the error "sorry, unimplemented: non-trivial designated initializers not supported" Not that intuitive...

Chilcote answered 8/4, 2017 at 13:6 Comment(1)
This reads as a comment on an Answer rather than an Answer to the Questioner's problem.Jaclin

© 2022 - 2024 — McMap. All rights reserved.