【问题标题】:Compile-time array selection in C++C++ 中的编译时数组选择
【发布时间】:2018-11-08 01:13:35
【问题描述】:

我有一个类,它根据编译时参数保存一个数组(用于过滤器)。例如:

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

例如,如果N=4Real = double,我希望m_h 是(比如说):

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

如果N=4Real = float,我愿意

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

如果N=6Real=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 可能会有一个更具表现力的解决方案。

【问题讨论】:

    标签: c++ templates c++17 constexpr template-specialization


    【解决方案1】:

    我不知道你到底想要什么,但是......我想你可以初始化 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(),您可以使用大量if constexpr编写单个bar()函数,如下所示

    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 ) ...
        }
     }
    

    【讨论】:

    • “我不确定你到底想要什么,但是……”这正是我想要的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2020-10-22
    • 1970-01-01
    • 2018-10-17
    相关资源
    最近更新 更多