Итерация по шаблону int

#c #templates #c 17 #template-meta-programming #boost-hana

#c #шаблоны #c 17 #шаблон-метапрограммирование #boost-hana

Вопрос:

У меня есть функция:

 template<class Real, int N>
constexpr std::array<Real, N> get_array();
  

и я хотел бы протестировать его на многих типах и многих целых числах. В псевдокоде:

 auto types = {float, double, long double};
for(int i = 0; i < 25;   i) {
   for (type : types) {
        auto arr = get_array<type, i>();
        // test arr
   }
}
  

Очевидно, что это не компилируется. Есть ли способ исправить цикл, чтобы я мог выполнять итерации по массиву?

Комментарии:

1. Вы хотите сделать это во время компиляции с помощью метапрограммирования шаблона.

2. Платформа GoogleTest имеет типизированные тесты и типизированные параметризованные тесты: github.com/google/googletest/blob/master/googletest/docs/… . Или, поскольку для тестирования требуется всего 3 типа, было бы не вредно просто выполнить get_array<float, i>; get_array<double,i> и т.д.

3. @PaulEvans: Да, я делаю.

4. @Yksisarvinen: Googletest — это здорово, но тест предназначен только для того, чтобы мотивировать цель.

Ответ №1:

Поскольку у вас есть Boost.В любом случае, Hana помечен, мы можем просто использовать его:

 auto types = hana::tuple_t<float, double, long double>;
hana::for_each(types, [](auto type){
    hana::for_each(std::make_index_sequence<25>(), [=](auto idx){
        // here type is an object that denotes the type and
        // idx is an integral constant that denotes the next value

        get_array<typename decltype(type)::type, idx>();
    });
});
  

Комментарии:

1. Просто для полноты картины, каков минимальный заголовок? (Я посмотрю это и отредактирую, если вы не знаете сразу.)

2. @user14717 <boost/hana.hpp> ?

3. Это заголовок aggregate; обычно я предпочитаю включать только ту часть библиотеки, которая мне нужна, чтобы контролировать время компиляции. Впрочем, это не имеет большого значения.

4. Я получаю: ошибка: ‘type_t’ не является членом ‘boost::hana’ с помощью g -8 и разработки hana.

5. уверен, что это tuple_t

Ответ №2:

Принятый ответ хорош, но если вы не хотите загрязнять свой стек вызовов, лучше выполнить всю возможную обработку, прежде чем переходить к фактическому материалу во время выполнения.

В приведенном здесь примере используется, hana::cartesian_product что, вероятно, излишне для специальных случаев использования, но вы могли бы использовать вложенные hana::unpack файлы для получения того же эффекта.

Вот рабочий пример:

https://godbolt.org/z/zKwpqe

 #include <array>
#include <boost/hana/assert.hpp>
#include <boost/hana/at.hpp>
#include <boost/hana/cartesian_product.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/for_each.hpp>
#include <boost/hana/range.hpp>
#include <boost/hana/transform.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/type.hpp>

namespace hana = boost::hana;

template <typename Real, int N>
constexpr std::array<Real, N> get_array() {
  return {};
}

int main() {
  auto types   = hana::tuple_t<float, double, long, double>;
  auto lengths = hana::to_tuple(hana::range_c<int, 0, 4>);
  auto tls = hana::cartesian_product(hana::make_tuple(types, lengths));
  auto get_array_fns = hana::transform(tls, [](auto pair) {
    return [] {
      return get_array<typename decltype( hana::at_c<0>(pair))::type,
                       decltype( hana::at_c<1>(pair))::value>();
      };
  });

  hana::for_each(get_array_fns, [](auto get_array) {
    auto arr = get_array();
    // test arr 
  });

  auto result_types = hana::unpack(get_array_fns, [](auto ...get_array) {
    return hana::tuple_t<decltype(get_array())...>;
  });

  BOOST_HANA_CONSTANT_CHECK(hana::equal(
    decltype(result_types){},
    hana::tuple_t<std::array<float,  0>,
                  std::array<float,  1>,
                  std::array<float,  2>,
                  std::array<float,  3>,
                  std::array<double, 0>,
                  std::array<double, 1>,
                  std::array<double, 2>,
                  std::array<double, 3>,
                  std::array<long,   0>,
                  std::array<long,   1>,
                  std::array<long,   2>,
                  std::array<long,   3>,
                  std::array<double, 0>,
                  std::array<double, 1>,
                  std::array<double, 2>,
                  std::array<double, 3>>));
}
  

Ответ №3:

Как насчет следующего (без boost)?

 #include <array>
#include <iostream>

template <typename T, std::size_t Dim>
constexpr std::array<T, Dim> get_array ()
 { return {}; }

// fake test
template <typename T, std::size_t Dim>
constexpr bool checkArray (std::array<T, Dim> const amp;)
 { return true; }

template <typename T, std::size_t ... Is>
constexpr bool checkSequence (std::index_sequence<Is...> const amp;)
 { return (... amp;amp; checkArray(get_array<T, Is>())); }

template <typename ... Ts>
constexpr bool checkTypes ()
 { return (... amp;amp; checkSequence<Ts>(std::make_index_sequence<25u>{})); }

int main ()
 {
   constexpr auto value = checkTypes<float, double, long double>();

   std::cout << value << std::endl;
 }