Выбор массива во время компиляции в C ++ - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть класс, который содержит массив (для фильтра) на основе параметров времени компиляции. Например:

template<class Real, unsigned N>
class foo {
public:
  // stuff ...
private:
   static const constexpr std::array<Real, unsigned N> m_h;
};

Например, если N=4 и Real = double, я бы хотел, чтобы m_h было (скажем):

m_h = {0.4829629131445341,  0.8365163037378079,  0.2241438680420133, -0.129409522551260};

и если N=4 и Real = float, я бы хотел

m_h = {0.4829629f, 0.8365163f, 0.2241438f, -0.1294095f};

Если N=6 и Real=double, я бы хотел, чтобы числа были совершенно другими:

m_h = {0.332670552950082615998, 0.806891509311092576494, 0.45987750211849157009, -0.1350110200102545886963899, -0.0854412738820266616928191, 0.0352262918857095366027};

Какой самый элегантный синтаксис для достижения этой цели? Самое близкое, что я нашел, - это квадратура Гаусса Boost , которая достигает цели, сначала классифицируя тип Real по количеству цифр и конвертируемости в числа типа float, double и long double. Затем он вводит класс foo_detail, который дает функции get_constants() и выбирает константы, необходимые во время выполнения. Boost, конечно, поддерживает множество компиляторов и их различные возможности C ++ 11, поэтому я чувствую, что может быть более выразительное решение с использованием (скажем) C ++ 17.

1 Ответ

0 голосов
/ 08 ноября 2018

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

Я имею в виду ... вы можете написать foo() следующим образом

template <typename Real, std::size_t N>
class foo
 {
   private:
      static constexpr std::array<Real, N> m_h { bar<Real, N>() };
 };

template <typename Real, std::size_t N>
constexpr std::array<Real, N> foo<Real, N>::m_h;

и написать набор bar() шаблонных функций следующим образом

template <typename Real, std::size_t N>
constexpr std::array<Real, N> bar ();

template <>
constexpr std::array<double, 4u> bar<double, 4u> ()
 { return { {0.4829629131445341,  0.8365163037378079,
             0.2241438680420133, -0.129409522551260} }; }

template <>
constexpr std::array<float, 4u> bar<float, 4u> ()
 { return { {0.4829629f, 0.8365163f, 0.2241438f, -0.1294095f} }; }

template <>
constexpr std::array<double, 6u> bar<double, 6u> ()
 { return { { 0.332670552950082615998,      0.806891509311092576494,
              0.45987750211849157009,      -0.1350110200102545886963899,
             -0.0854412738820266616928191,  0.0352262918857095366027} }; }

// as many `bar()` specializations as you want

Ниже приведен полный пример компиляции (с упрощенным foo)

#include <array>
#include <iostream>

template <typename Real, std::size_t N>
constexpr std::array<Real, N> bar ();

template <>
constexpr std::array<double, 4u> bar<double, 4u> ()
 { return { {0.4829629131445341,  0.8365163037378079,
             0.2241438680420133, -0.129409522551260} }; }

template <>
constexpr std::array<float, 4u> bar<float, 4u> ()
 { return { {0.4829629f, 0.8365163f, 0.2241438f, -0.1294095f} }; }

template <>
constexpr std::array<double, 6u> bar<double, 6u> ()
 { return { { 0.332670552950082615998,      0.806891509311092576494,
              0.45987750211849157009,      -0.1350110200102545886963899,
             -0.0854412738820266616928191,  0.0352262918857095366027} }; }

template <typename Real, std::size_t N>
struct foo
 {
   static constexpr std::array<Real, N> m_h { bar<Real, N>() };
 };

template <typename Real, std::size_t N>
constexpr std::array<Real, N> foo<Real, N>::m_h;

int main ()
 {
   for ( auto f : foo<double, 4u>::m_h )
      std::cout << f << ' ';

   std::cout << std::endl;

   for ( auto f : foo<float, 4u>::m_h )
      std::cout << f << ' ';

   std::cout << std::endl;

   for ( auto f : foo<double, 6u>::m_h )
      std::cout << f << ' ';

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

Или, может быть, если вы не хотите разрабатывать bar() с помощью полной специализации, вы можете написать одну bar() функцию, используя множество if constexpr следующим образом

template <typename Real, std::size_t N>
constexpr std::array<Real, N> bar ()
 {
   if constexpr ( std::is_same<long double, Real>::value )
    {
      if constexpr ( 4u == N )
         return { /* something */ };
      else if constexpr ( 6u == N )
         return { /* something */ };
      // else if constexpr ( ?? == N ) ...
    }
   else if constexpr ( std::is_same<double, Real>::value )
    { 
      if constexpr ( 4u == N )
         return { {0.4829629131445341,  0.8365163037378079,
                   0.2241438680420133, -0.129409522551260} }; 
      else if constexpr ( 6u == N )
         return { { 0.332670552950082615998,      0.806891509311092576494,
                    0.45987750211849157009,      -0.1350110200102545886963899,
                   -0.0854412738820266616928191,  0.0352262918857095366027} }; 
      // else if constexpr ( ?? == N ) ...
    }
   else if constexpr ( std::is_same<float, Real>::value )
    { 
      if constexpr ( 4u == N )
         return { {0.4829629f, 0.8365163f, 0.2241438f, -0.1294095f} };
      else if constexpr ( 6u == N )
         return { /* something */ };
      // else if constexpr ( ?? == N ) ...
    }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...