C++双精度作为模板参数的解决方法

C++ workaround for doubles as template parameters

本文关键字:参数 解决 方法 双精度 C++      更新时间:2023-10-16

我知道双精度不能是模板参数,所以我正在寻找另一种方法来创建具有多个参数的函数。我当前(显然是错误的)代码如下所示:

template<double B1, double B2, double B3, double C1, double C2, double C3>
double sellmeier(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
}

有没有办法创建一个函数,该函数接受多个非整数类型参数和一个参数,而无需使每个参数都成为参数?

这里你想要的是一个策略类,它将为你的函数提供所需的值(SpecificConstants)。

struct SpecificConstants
{
static constexpr double b1 { 0.6961663 };
static constexpr double b2 { 0.4079426 };
static constexpr double b3 { 0.8974794 };
static constexpr double c1 { 0.0684043 * 0.0684043 };
static constexpr double c2 { 0.1162414 * 0.1162414 };
static constexpr double c3 { 9.896161 * 9.896161 };
};

您的函数只需要此策略类 (Constants)

template< typename Constants >
double sellmeier( const double wavelength )
{
double refractive_index_sq = 1;
double lambda_sq           = std::pow( wavelength, 2 );
refractive_index_sq += Constants::b1 * lambda_sq / ( lambda_sq - Constants::c1 );
refractive_index_sq += Constants::b2 * lambda_sq / ( lambda_sq - Constants::c2 );
refractive_index_sq += Constants::b3 * lambda_sq / ( lambda_sq - Constants::c3 );
return refractive_index_sq;
}

然后,可以像这样调用该函数:

sellmeier< SpecificConstants >( 2.0 );

在 c++14 中,您可以执行以下操作,为简洁起见,使用一个参数显示:

constexpr double GetB1(int b1Index)
{
switch (b1Index)
{
case 0: return 1.2345;
case 1: return 2.3456;
default: return 3.4567;
}
}
template<int B1Index>
double obviouslyNotSellmeier(const double wavelength) {
return wavelength * GetB1(B1Index);
}
obviouslyNotSellmeier<1>(0.123)

虽然它对调用者变得非常不友好。

有没有办法创建一个函数,该函数接受多个非整数类型参数和一个参数,而无需使每个参数都成为参数?

我不知道这是否是一个好主意,但是...是的,我想您可以将浮点值包装为常量staticstruct

从 C++11 (constexpr) 开始,您可以简单地定义

struct X1 { static constexpr double value { 1.2 }; };
struct X2 { static constexpr double value { 2.3 }; };
struct X3 { static constexpr double value { 3.4 }; };
struct Y1 { static constexpr double value { 4.5 }; };
struct Y2 { static constexpr double value { 5.6 }; };
struct Y3 { static constexpr double value { 6.7 }; };

将它们作为模板参数传递给sellmeier()

sellmeier<X1, X2, X3, Y1, Y2, Y3>(1.0);

并使用sellmeier()中的类型value

template <typename B1, typename B2, typename B3,
typename C1, typename C2, typename C3>
double sellmeier (const double wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1::value*lambda_sq/(lambda_sq-C1::value);
refractive_index_sq += B2::value*lambda_sq/(lambda_sq-C2::value);
refractive_index_sq += B3::value*lambda_sq/(lambda_sq-C3::value);
return refractive_index_sq;
}

在 C++11 之前(没有可用的constexpr),定义包装结构的语法有点烦人:您必须在结构体之外初始化const

struct X1 { static double const value; };
struct X2 { static double const value; };
struct X3 { static double const value; };
struct Y1 { static double const value; };
struct Y2 { static double const value; };
struct Y3 { static double const value; };
double const X1::value = 1.2;
double const X2::value = 2.3;
double const X3::value = 3.4;
double const Y1::value = 4.5;
double const Y2::value = 5.6;
double const Y3::value = 6.7;

由于我在编译时不需要参数,我意识到函子是更好/正确的解决方案:

struct sellmeier {
sellmeier(double B1, double B2, double B3, double C1, double C2, double C3) :
B1(B1), B2(B2), B3(B3), C1(C1), C2(C2), C3(C3) {}
double operator()(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1 * lambda_sq / (lambda_sq - C1);
refractive_index_sq += B2 * lambda_sq / (lambda_sq - C2);
refractive_index_sq += B3 * lambda_sq / (lambda_sq - C3);
return refractive_index_sq;
}
private:
double B1, B2, B3, C1, C2, C3;
};
//functor with sellmeier coefficients for fused quartz
auto sellmeier_fused_quartz = sellmeier(0.6961663, 0.4079426, 0.8974794, 0.0684043*0.0684043, 0.1162414*0.1162414, 9.896161*9.896161);

由于我在编译时不需要参数,我意识到函子是更好/正确的解决方案

在这种情况下,如果你可以使用C++11,你可以简单地编写一个lambda

#include <cmath>
int main ()
{
auto B1=0.6961663;
auto B2=0.4079426;
auto B3=0.8974794;
auto C1=0.0684043*0.0684043;
auto C2=0.1162414*0.1162414;
auto C3=9.896161*9.896161;
auto sellmeier = [=] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}

从 C++14 开始,您可以简化(恕我直言)如下

#include <cmath>
int main ()
{
auto sellmeier = [B1=0.6961663,
B2=0.4079426,
B3=0.8974794,
C1=0.0684043*0.0684043,
C2=0.1162414*0.1162414,
C3=9.896161*9.896161] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}