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]+平均系数));
}
总和*=比例因子;
回报金额;
}
请注意,如果没有consteprsqrt
(其中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;
}