Нетривиальные назначенные инициализаторы не поддерживаются

У меня есть структура следующим образом:

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;

};

Когда я пытаюсь инициализировать его таким образом:

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

Я получаю эту ошибку:

sorry, unimplemented: non-trivial designated initializers not supported

Я думаю, что он хочет порядок инициализации точно так, как он объявлен, и local_connection отсутствует. Мне не нужно его инициализировать, и установка его в NULL не работает.

Если я изменю его на g++, все равно получите ту же ошибку:

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

Ответ 1

Это не работает с g++. Вы по существу используете C-конструкции с С++. Пара способов обойти его.

1) Удалите "." и при инициализации измените значение "=" на ":".

#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) Используйте g++ -X c. (Не рекомендуется) или поместить этот код в extern C [Отказ от ответственности, я не тестировал это]

Ответ 2

порядок инициализации должен быть в точном порядке объявления.

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

Я понимаю, что это означает, что компилятор не поддерживает инициализацию, основанную на именах, вне порядка,

Нужно инициализировать структуру по-старому. Я сохраняю имена переменных для ясности, но я должен их инициализировать по порядку и не пропускать переменную.

Я могу остановить инициализацию при любой переменной, но не могу инициализировать переменные, которые из этого.

Ответ 3

Я заметил, что мой компилятор GCC имеет некоторый трюк, чтобы принять .fieldname = значения, но будет компилироваться только в том случае, если поля находятся в том же порядке, в котором они объявлены в структуре.

Мне удалось запустить эту структуру двумя способами. Имя с именами улучшает читаемость и снижает риск присвоения неверных данных, если впоследствии изменится порядок полей структуры.

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

Правило большого пальца:

  • Назначить поля .name = value
  • Назначьте в том порядке, в котором они объявлены
  • Включить все поля в настройке

Ответ 4

К сожалению, С++ не поддерживает назначенные инициализаторы. GCC по-прежнему позволяет использовать их (в качестве расширения), но вы должны инициализировать элементы в том же порядке, что и в struct.

Другим обходным решением является использование немедленно вызываемой лямбда:

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

Я лично предпочитаю это решение, потому что он совершенно стандартный С++, он позволяет вам инициализировать поля в нужном вам порядке, пропустить те, которые вам не нужны, и по умолчанию инициализировать остальные. И компилятор по-прежнему способен оптимизировать это. Обратите внимание, что это будет работать только с С++ 17 или новее.

Ответ 5

Поскольку ни один из других подходов не работал у меня с Arduino IDE, я решил просто установить каждое поле отдельно:

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;

Ответ 6

Также обратите внимание, что, как изложено первоначальным вопросом, имеет значение порядок выражений членов. Я заметил, что если бы я хотел только инициализировать "размер" в предыдущем примере, мне нужно поставить выражения для .port и .ib_port раньше. В противном случае я получаю ошибку "извините, не реализовано: нетривиальные назначенные инициализаторы не поддерживаются" Не то, что интуитивно...