non-trivial designated initializers not supported

Publish date: 2024-06-10

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

7 Answers

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.

3

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]

12

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:

  • Assign to .name=value fields
  • Assign in the order they where declared
  • Include all fields in the assigment
  • 2

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

    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.

    2

    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.

    0

    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...

    1

    ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoampqYWqGeH2Op6anZaSntre1wKVknZ2jnrSvrdOem2ahnp7Bqq3LorGeqqNiu7DAjKysqaifp8GmsA%3D%3D