Расширение designated initialization для заполнения отдельных полей полей.
Предложение
Предположим, у нас есть структура 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
};
Если поле - композиция, то странно, что там только один элемент композиции инициализируется. Скорей всего это значит что у нас какой-то частный случай. Чаще требуется инициализировать несколько полей структуры и синтаксис с фигурными скобками не является избыточным в таком случае:
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);
// Ваше предложение похоже на 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);