Фон
Предположим, что я пытаюсь реализовать многомерный массив фиксированного размера, используя плоский массив:
template <class T, std::size_t... Dims>
struct multi_array {
static constexpr std::size_t size() noexcept
{
return (Dims * ... * std::size_t{1});
}
std::array<T, size()> _elems;
};
Элемент _elems
сделан publi c чтобы включить агрегатную инициализацию для не копируемых, неподвижных типов: (предположим, что non_movable
имеет явный конструктор (int)
)
multi_array<non_movable, 2, 3> arr {
non_movable(0), non_movable(1), non_movable(2),
non_movable(3), non_movable(4), non_movable(5)
};
Это компилируется благодаря C ++ 17 гарантированному исключению копирования - соответствующие элементы _elems
непосредственно инициализируются из нематериализованных значений pr, не требуя конструкторов перемещения.
Задача
Теперь проблема заключается в том, что в приведенном выше объявлении многомерный массив инициализируется как одномерный массив. Я буду называть это «плоской инициализацией», в отличие от «вложенной инициализации»:
multi_array<non_movable, 2, 3> arr {
{ non_movable(0), non_movable(1), non_movable(2) },
{ non_movable(3), non_movable(4), non_movable(5) }
}; // error: too many initializers for 'multi_array<non_movable, 3, 2>'
Как мы можем включить вложенную инициализацию без необходимости изменения базового контейнера, используемого для реализации multi_array
из одномерного массива в многомерный массив?
Я предполагаю, что для этого потребуется собственный конструктор, но я понятия не имею, как "прозрачно" пропустить нематериализованные значения через конструкторы. Все, что я могу придумать, это создать из них параметр, а затем перейти от параметра, который не работает для неподвижных типов.
Пример минимального воспроизведения
#include <array>
#include <cstddef>
struct non_movable {
explicit non_movable(int) {}
non_movable(const non_movable&) = delete;
non_movable(non_movable&&) = delete;
non_movable& operator=(const non_movable&) = delete;
non_movable& operator=(non_movable&&) = delete;
~non_movable() = default;
};
template <class T, std::size_t... Dims>
struct multi_array {
static constexpr std::size_t size() noexcept
{
return (Dims * ... * std::size_t{1});
}
std::array<T, size()> _elems;
};
int main()
{
multi_array<non_movable, 3, 2> arr {
non_movable(0), non_movable(1), non_movable(2),
non_movable(3), non_movable(4), non_movable(5)
};
// multi_array<non_movable, 3, 2> arr {
// { non_movable(0), non_movable(1), non_movable(2) },
// { non_movable(3), non_movable(4), non_movable(5) }
// };
(void)arr;
}
( live демо )