ideas icon indicating copy to clipboard operation
ideas copied to clipboard

Расширение designated initialization для заполнения отдельных полей полей.

Open dasfex opened this issue 1 year ago • 2 comments

Предложение

Предположим, у нас есть структура B, которая содержит поле типа A:

struct A { int x; int y; };
struct B {
  A a;
  int z;
}

Сейчас, если я хочу использовать designated initialization для объекта типа B, мне нужно расписать поле a отдельно:

B b = B{
  .a = A{
    .x = 123
  },
  .z = 3
}

Из-за этого появляется некоторая лишня вложенность.

Предлагается поддержать C-style подход. где в designated initialization можно использовать вложенные поля:

B b = B{
  .a.x = 123,
  .z = 3
}

Подразумевается, что код выше является синтаксическим сахаром для работающего варианта. Все незадействованные поля заполняются аналогично текущей реализации с zero initialisation.

Где может быть полезно

В небезызвестном фреймворке userver (по крайней мере внутри) при собирании реквеста для похода в эндпоинт другого сервиса часто приходится делать что-то такое:

Request request;
request.auth_context = auth_context;
request.body = Request::Body {
  .field = value1,
  .val = value2
};

или такого:

Request request{
  .auth_context = auth_context,
  .body = Request::Body{
    .field = value1,
    .val = value2
  }
};

Хотя можно обойтись таким:

Request request{
  .auth_context = auth_context,
  .body.field = value1,
  .body.value = value2
};

dasfex avatar Sep 28 '24 13:09 dasfex

Если поле - композиция, то странно, что там только один элемент композиции инициализируется. Скорей всего это значит что у нас какой-то частный случай. Чаще требуется инициализировать несколько полей структуры и синтаксис с фигурными скобками не является избыточным в таком случае:

    vk::ImageCreateInfo imageCreateInfo = {
        .flags = {},
        .imageType = vk::ImageType::e2D,
        .format = format,
        .extent = {
            .width = size.width,
            .height = size.height,
            .depth = 1,
        },
        .mipLevels = 1,
        .arrayLayers = 1,
        .samples = vk::SampleCountFlagBits::e1,
        .tiling = vk::ImageTiling::eOptimal,
        .usage = imageUsage,
        .sharingMode = vk::SharingMode::eExclusive,
        .initialLayout = vk::ImageLayout::eUndefined,
    };
    imageCreateInfo.setQueueFamilyIndices(queueFamilyIndex);

tomilov avatar Sep 28 '24 14:09 tomilov

// Ваше предложение похоже на C-style designated initialization, // но в C++ пока что такой синтаксис не поддерживается на уровне стандарта. // Однако можно использовать user-defined конструкторы или вспомогательные функции:

struct A { int x = 0; int y = 0; };

struct B { A a; int z = 0; };

// 1. Вариант: Используем конструктор с default параметрами struct B_v2 { A a; int z;

// Конструктор позволяет передавать только нужные значения
B_v2(int ax = 0, int ay = 0, int z_val = 0) : a{ax, ay}, z{z_val} {}

};

// Использование: B_v2 b1(123, 0, 3);

// 2. Вариант: Используем factory-функцию B make_B(int ax, int z_val) { B b{}; b.a.x = ax; b.z = z_val; return b; }

// Использование: B b2 = make_B(123, 3);

he090279kap avatar Feb 03 '25 17:02 he090279kap