Есть ли способ построить из initializer_list во время компиляции?

#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. Поддержано, так как это полезный вопрос, хотя по какой-то причине меня раздражает выражение глупый компилятор