我有一个类,该类根据编译时参数保存一个数组(用于过滤器)。例如:
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的Gaussian quadrature,它通过首先按位数对Real
类型进行分类并将其转换为float,double和long double来实现目标。然后,它引入一个foo_detail
类,该类提供函数get_constants()
并选择运行时所需的常量。 Boost当然支持许多编译器及其不同的C ++ 11功能,所以我觉得使用(比如说)C ++ 17可能会有更具表现力的解决方案。
答案 0 :(得分:3)
不确定我确切地了解您想要什么,但是...我想您可以初始化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 ) ...
}
}