#c #templates #c 20 #constexpr
Вопрос:
Я пишу класс C ndarray. Мне нужны массивы как динамического размера, так и известного размера во время компиляции (выделенное свободное хранилище и выделенный стек соответственно). Я хочу поддержать инициализацию из вложенных std::initializer_list
.
Динамический размер в порядке: это отлично работает.
frozenca::Arraylt;float, 2gt; arr {{1, 2, 3}, {4, 5, 6}}; std::cout lt;lt; arr.size() lt;lt; 'n'; // 6 std::cout lt;lt; arr[{1, 1}] lt;lt; 'n'; // 5
Статический размер тоже в порядке: это отлично работает.
frozenca::StaticArraylt;float, 2, 3gt; arr2 {{1, 2, 3}, {4, 5, 6}}; std::cout lt;lt; arr2.size() lt;lt; 'n'; // 6 std::cout lt;lt; arr2[{1, 1}] lt;lt; 'n'; // 5
Но я ненавижу, что инициализация на самом деле выполняется во время выполнения. Я хочу сделать это как операцию во время компиляции. Мои детали реализации заключаются в следующем:
template lt;std::semiregular T, std::size_t Ngt; using DenseInitializer_t = typename DenseInitializerlt;T, Ngt;::type; template lt;std::semiregular T, std::size_t Ngt; struct DenseInitializer { using type = std::initializer_listlt;DenseInitializer_tlt;T, N - 1gt;gt;; }; template lt;std::semiregular Tgt; struct DenseInitializerlt;T, 1gt; { using type = std::initializer_listlt;Tgt;; }; template lt;std::semiregular Tgt; struct DenseInitializerlt;T, 0gt;; template lt;std::semiregular Scalar, int... Sizesgt; template lt;typename Initializergt; constexpr void StaticArraylt;Scalar, Sizes...gt;::verifyDims(const Initializeramp; init) const { checkDimslt;0, Initializer, Sizes...gt;(init); } template lt;std::semiregular Scalar, int... Sizesgt; StaticArraylt;Scalar, Sizes...gt;::StaticArray(DenseInitializer_tlt;value_type, Ngt; init) { verifyDims(init); insertFlat(data(), init); } template lt;typename Initializergt; constexpr bool checkNonJagged(const Initializeramp; init) { auto i = std::cbegin(init); return std::all_of(init.begin(), init.end(), [amp;i](const autoamp; it) { return it.size() == i-gt;size(); }); } template lt;int k, typename Initializer, int... Sizesgt; void checkDims(const Initializeramp; init) { if constexpr (k lt; sizeof...(Sizes) - 1) { if (!checkNonJagged(init)) { throw std::invalid_argument("Jagged matrix initializer"); } } if (std::getlt;kgt;(std::forward_as_tuple(Sizes...)) != std::ssize(init)) { throw std::invalid_argument("Matrix initializer does not match with static matrix"); } if constexpr (k lt; sizeof...(Sizes) - 1) { checkDimslt;k 1, decltype(*std::begin(init)), Sizes...gt;(*std::begin(init)); } } template lt;std::semiregular Tgt; void addList(T* data, const T* first, const T* last, intamp; index) { for (; first != last; first) { data[index] = *first; index; } } template lt;std::semiregular T, typename Igt; void addList(T* data, const std::initializer_listlt;Igt;* first, const std::initializer_listlt;Igt;* last, intamp; index) { for (; first != last; first) { addList(data, first-gt;begin(), first-gt;end(), index); } } template lt;std::semiregular T, typename Igt; void insertFlat(T* data, std::initializer_listlt;Igt; list) { int index = 0; addList(data, std::begin(list), std::end(list), index); }
addList
и checkNonJagged
не работает во время компиляции, потому что глупый компилятор думает, что init
это не называется временем компиляции даже в примере.
Как я могу сделать это как операцию во время компиляции?
Комментарии:
1. Поддержано, так как это полезный вопрос, хотя по какой-то причине меня раздражает выражение глупый компилятор