У меня есть класс, который содержит массив (для фильтра) на основе параметров времени компиляции. Например:
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.





Не уверен, что я понимаю, что именно вы хотите, но ... Я полагаю, вы можете инициализировать 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 ) ...
}
}
«Не уверен, что понимаю, что именно ты хочешь, но ...» это именно то, что я хочу. Спасибо!