C++ 如果需要,使用constexpr定义并声明一个const std::数组

C++ 如果需要,使用constexpr定义并声明一个const std::数组,c++,arrays,stl,containers,constexpr,C++,Arrays,Stl,Containers,Constexpr,我试图实现高斯-勒让德求积,我想要一个模板函数 它将点数作为模板参数。 现在我有这个: 模板 双高斯正交积分核(double(*f)(double),double from,double to){ 双比例系数=(至自)/2; 双平均_系数=(从+到)/2; std::数组因子; std::数组点; if constexpr(正交点的个数=2){ 因子={1,1}; 点={-1.0/sqrt(3),1.0/sqrt(3)}; } if constexpr(正交点的个数=3){ 因子={5.0/9.

我试图实现高斯-勒让德求积,我想要一个模板函数 它将点数作为模板参数。 现在我有这个:

模板
双高斯正交积分核(double(*f)(double),double from,double to){
双比例系数=(至自)/2;
双平均_系数=(从+到)/2;
std::数组因子;
std::数组点;
if constexpr(正交点的个数=2){
因子={1,1};
点={-1.0/sqrt(3),1.0/sqrt(3)};
}
if constexpr(正交点的个数=3){
因子={5.0/9.0,8.0/9.0,5.0/9.0};
点={-sqrt(3.0/5.0),0,sqrt(3.0/5.0)};
}
双和=0;
对于(int i=0;i<正交点的个数;i++){
总和+=在(i)处的因子)*((*f)(比例因子*在(i)处的点数)+平均因子);
}
总和*=比例因子;
回报金额;
}
如您所见,当模板参数更改时,不仅数组大小会更改,内容也会更改,但对于给定的大小,内容是众所周知的。出于这个原因,我认为如果std::array是const static会更好,因为函数被多次调用


现在我只设法使用if-constexpr来声明数组,但是如何使用它来定义和声明数组,使其在if-constexpr范围外可见,并且数组只定义一次?

添加两个帮助函数就足够了(如果您使用的是C++20):

…或如果以后要进行专门化,请使用SFINAE阻止匹配:

#include <type_traits>

template<unsigned number_of_quadrature_points>
std::enable_if_t<number_of_quadrature_points==2||number_of_quadrature_points==3,
                 double>
gaussian_quadrature_integral_core(double (*f)(double), double from,
                                                       double to)
{
#包括
模板
std::如果启用,则启用
高斯正交积分核(double(*f)(double),double from,
双到双)
{

您可以在本主题中使用类似的内容:

因此,我们正在使用和SFINAE创建两个模板专业化。我们通过模板参数数量和正交点数量来区分它们。这样我们就可以得到全局参数,而不必多次定义和实例化。此代码使用c++17编译

我还建议使用现代方法,而不是指针指向函数

#include <array>
#include <cmath>
#include <iostream>
#include <functional>

template<int number_of_quadrature_points, typename E=void>
struct gaussian_quadrature_params
{

};

template<int number_of_quadrature_points>
struct gaussian_quadrature_params<number_of_quadrature_points, std::enable_if_t<(number_of_quadrature_points==2)> >
{
    constexpr static const std::array<double, number_of_quadrature_points> factors = {1, 1};
    constexpr static const std::array<double, number_of_quadrature_points> points = {-1.0/sqrt(3), 1.0/sqrt(3)};
};

template<int number_of_quadrature_points>
struct gaussian_quadrature_params<number_of_quadrature_points, std::enable_if_t<(number_of_quadrature_points==3)> >
{
    constexpr static const std::array<double, number_of_quadrature_points> factors = {5.0/9.0, 8.0/9.0, 5.0/9.0};
    constexpr static const std::array<double, number_of_quadrature_points> points = {-sqrt(3.0/5.0), 0, sqrt(3.0/5.0)};
};


double f(double x)
{
    return x;
}


template<int number_of_quadrature_points>
double gaussian_quadrature_integral_core(std::function<double(double)> f, double from, double to){
    double scaling_factor = (to-from)/2;   
    double average_factor = (from+to)/2;
    
    double sum = 0;

    for(int i = 0; i < number_of_quadrature_points; i++){
        sum += gaussian_quadrature_params<number_of_quadrature_points>::factors.at(i)*(f(scaling_factor*gaussian_quadrature_params<number_of_quadrature_points>::points.at(i)+average_factor));
    }

    sum *= scaling_factor;
    return sum;
}

int main()
{
   std::cout << gaussian_quadrature_integral_core<2>(f, -1.0, 1.0) << std::endl;
   std::cout << gaussian_quadrature_integral_core<3>(f, -1.0, 1.0) << std::endl;
}
#包括
#包括
#包括
#包括
模板
结构高斯正交参数
{
};
模板
结构高斯正交参数
{
constexpr static const std::array factors={1,1};
constexpr static const std::array points={-1.0/sqrt(3),1.0/sqrt(3)};
};
模板
结构高斯正交参数
{
constexpr static const std::array factors={5.0/9.0,8.0/9.0,5.0/9.0};
constexpr static const std::array points={-sqrt(3.0/5.0),0,sqrt(3.0/5.0)};
};
双f(双x)
{
返回x;
}
模板
双高斯正交积分核(标准::函数f,双from,双to){
双比例系数=(至自)/2;
双平均_系数=(从+到)/2;
双和=0;
对于(int i=0;i<正交点的个数;i++){
总和+=高斯正交参数::因子(i)*(f(比例因子*高斯正交参数::点(i)+平均因子));
}
总和*=比例因子;
回报金额;
}
int main()
{

std::cout您可能有模板变量:

template <std::size_t N>
static constexpr std::array<double, N> factors;

template <std::size_t N>
static constexpr std::array<double, N> points;

template <>
constexpr std::array<double, 2> factors<2>{{1, 1}};
template <>
constexpr std::array<double, 2> points<2>{{-1.0 / sqrt(3), 1.0 / sqrt(3)}};

template <>
constexpr std::array<double, 3> factors<3>{{5.0 / 9.0, 8.0 / 9.0, 5.0 / 9.0}};
template <>
constexpr std::array<double, 3> points<3>{{-sqrt(3.0 / 5.0), 0, sqrt(3.0 / 5.0)}};
模板
静态constexpr std::数组因子;
模板
静态constexpr std::数组点;
模板
constexpr std::数组因子{{1,1};
模板
constexpr std::数组点{{-1.0/sqrt(3),1.0/sqrt(3)};
模板
constexpr std::数组因子{{5.0/9.0,8.0/9.0,5.0/9.0};
模板
constexpr std::数组点{{-sqrt(3.0/5.0),0,sqrt(3.0/5.0)};
然后

template<int number_of_quadrature_points>
double gaussian_quadrature_integral_core(double (*f)(double), double from, double to)
{
    const double scaling_factor = (to - from) / 2;   
    const double average_factor = (from + to) / 2;
    double sum = 0;

    for(int i = 0; i < number_of_quadrature_points; i++){
        sum += factors<number_of_quadrature_points>[i]
           * ((*f)(scaling_factor * points<number_of_quadrature_points>[i] + average_factor));
    }

    sum *= scaling_factor;
    return sum;
}
模板
双高斯正交积分核(double(*f)(double),double from,double to)
{
常数双比例系数=(到-从)/2;
常数双平均系数=(从+到)/2;
双和=0;
对于(int i=0;i<正交点的个数;i++){
总和+=系数[i]
*((*f)(比例系数*点[i]+平均系数));
}
总和*=比例因子;
回报金额;
}


请注意,如果没有constepr
sqrt
(其中
std:
不是),您必须将
constepr
替换为
constepr

如果有人使用与2或3不同的N调用您的函数,会发生什么情况?
如果constepr
很好,但我会选择一个专门的模板(用于系数/点选择)@Cedric这确实是一个问题,现在我只想做一个静态断言,但我会重新考虑,因为你的评论让我意识到这样的解决方案可能并不优雅。我也想到了类似的事情,但我在想,如果没有helper函数,这是否是可能的。不过这仍然是一个很好的解决方案,谢谢你。@KarolSzustakowski如果您愿意,可以使用lambdas。您可以使用enabler(您可以保留enabler以允许使用实数公式(奇数大于42))……专门化
模板结构高斯正交参数,甚至在C++14中也可以使用,这很好。
template <std::size_t N>
static constexpr std::array<double, N> factors;

template <std::size_t N>
static constexpr std::array<double, N> points;

template <>
constexpr std::array<double, 2> factors<2>{{1, 1}};
template <>
constexpr std::array<double, 2> points<2>{{-1.0 / sqrt(3), 1.0 / sqrt(3)}};

template <>
constexpr std::array<double, 3> factors<3>{{5.0 / 9.0, 8.0 / 9.0, 5.0 / 9.0}};
template <>
constexpr std::array<double, 3> points<3>{{-sqrt(3.0 / 5.0), 0, sqrt(3.0 / 5.0)}};
template<int number_of_quadrature_points>
double gaussian_quadrature_integral_core(double (*f)(double), double from, double to)
{
    const double scaling_factor = (to - from) / 2;   
    const double average_factor = (from + to) / 2;
    double sum = 0;

    for(int i = 0; i < number_of_quadrature_points; i++){
        sum += factors<number_of_quadrature_points>[i]
           * ((*f)(scaling_factor * points<number_of_quadrature_points>[i] + average_factor));
    }

    sum *= scaling_factor;
    return sum;
}