Simplify template function by passing a template as argument possible? - c++

I wrote a smal example illustrating the problem. solve_bs1_y and solve_bs2_y are implemented completely similar. The only difference is the function call: solve_bs*_z. Unfortunately, it seems impossible to pass a template as argument to replace the function call of solve_bs*_z. Consequently, I have to implement for each solve_bs*_z another solve_bs*_y. Is there a way to simplify the code so that I need just one implementation of solve_bs_y?
// Example program
#include <iostream>
#include <string>
template <int x, int y, int offs, class T>
float solve_bs1_z(T mat, float fS, float fT, float fU) {
return 1; // to keep it simple
}
template <int x, int y, int offs, class T>
float solve_bs2_z(T mat, float fS, float fT, float fU) {
return 2; // to keep it simple
}
// essentially the same as solve_bs2_y
template <int x, int offs, class T>
float solve_bs1_y(T mat, float fS, float fT, float fU) {
const float bs_s = 2;
return ( solve_bs1_z<x, 0, offs>(mat, fS, fT, fU)
+ solve_bs1_z<x, 1, offs>(mat, fS, fT, fU)
+ solve_bs1_z<x, 2, offs>(mat, fS, fT, fU))
* bs_s;
}
// essentially the same as solve_bs1_y
template <int x, int offs, class T>
float solve_bs2_y(T mat, float fS, float fT, float fU) {
const float bs_s = 2;
return ( solve_bs2_z<x, 0, offs>(mat, fS, fT, fU)
+ solve_bs2_z<x, 1, offs>(mat, fS, fT, fU)
+ solve_bs2_z<x, 2, offs>(mat, fS, fT, fU) )
* bs_s;
}
// these are called in the program ..
template<int offs, class T>
float solve_ffd_bs1(T mat, float fS, float fT, float fU) {
return solve_bs1_y<0, offs>(mat, fS, fT, fU) +
solve_bs1_y<1, offs>(mat, fS, fT, fU) +
solve_bs1_y<2, offs>(mat, fS, fT, fU);
}
template<int offs, class T>
float solve_ffd_bs2(T mat, float fS, float fT, float fU) {
return solve_bs2_y<0, offs>(mat, fS, fT, fU) +
solve_bs2_y<1, offs>(mat, fS, fT, fU) +
solve_bs2_y<2, offs>(mat, fS, fT, fU);
}
int main()
{
int mat[3][3][3] = {
{{1,2,3}, {4,5,6}, {7,8,9}},
{{11,2,3}, {14,5,6}, {17,8,9}},
{{21,2,3}, {24,5,6}, {27,8,9}}
};
solve_ffd_bs2<0>(mat, 1,2,3);
return 0;
}

The wrapper version without struct templates:
struct s1 {
template <int x, int y, int offs, class T>
static float solve_bs_z(T mat, float fS, float fT, float fU) {
return 1; // to keep it simple
}
};
struct s2 {
template <int x, int y, int offs, class T>
static float solve_bs_z(T mat, float fS, float fT, float fU) {
return 2; // to keep it simple
}
};
template <class Wrapper, int x, int offs, class T>
float solve_bs_y(T mat, float fS, float fT, float fU) {
const float bs_s = 2;
return ( Wrapper::template solve_bs_z<x, 0, offs>(mat, fS, fT, fU)
+ Wrapper::template solve_bs_z<x, 1, offs>(mat, fS, fT, fU)
+ Wrapper::template solve_bs_z<x, 2, offs>(mat, fS, fT, fU))
* bs_s;
}
and then call:
solve_bs_y<s1, 0, 1>(...);

Related

Nonlinear least-squares fitting with two independent variables in C++: implementing GSL algorithm

Following up to a previous question I asked in Fixing parameters of a fitting function in Nonlinear Least-Square GSL (successfully answered by #zkoza), I would like to implement an algorithm that can fit data to a non-linear function, by fixing some of its parameters while leaving other parameters to change for finding the best fit to the data. The difference to my previous question is that I want to have two independent variables instead of one independent variable.
Non-linear function used to fit the data
double gaussian(double x, double b, double a, double c)
{
const double z = (x - b) / c;
return a * std::exp(-0.5 * z * z);
}
In my previous question I was considering that x was the only independent variable. Now I would like to consider two independent variables, x and b.
The original algorithm used to fit a non-linear function using only one independent variable (while fixing variable a) is a C++ wrapper of the GSL nonlinear least-squares algorithm (borrowed from https://github.com/Eleobert/gsl-curve-fit/blob/master/example.cpp):
template <typename F, size_t... Is>
auto gen_tuple_impl(F func, std::index_sequence<Is...> )
{
return std::make_tuple(func(Is)...);
}
template <size_t N, typename F>
auto gen_tuple(F func)
{
return gen_tuple_impl(func, std::make_index_sequence<N>{} );
}
template <class R, class... ARGS>
struct function_ripper {
static constexpr size_t n_args = sizeof...(ARGS);
};
template <class R, class... ARGS>
auto constexpr n_params(R (ARGS...) )
{
return function_ripper<R, ARGS...>();
}
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>
{
// This specifies a trust region method
const gsl_multifit_nlinear_type *T = gsl_multifit_nlinear_trust;
const size_t max_iter = 200;
const double xtol = 1.0e-8;
const double gtol = 1.0e-8;
const double ftol = 1.0e-8;
auto *work = gsl_multifit_nlinear_alloc(T, params, fdf->n, fdf->p);
int info;
// initialize solver
gsl_multifit_nlinear_init(initial_params, fdf, work);
//iterate until convergence
gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol, nullptr, nullptr, &info, work);
// result will be stored here
gsl_vector * y = gsl_multifit_nlinear_position(work);
auto result = std::vector<double>(initial_params->size);
for(int i = 0; i < result.size(); i++)
{
result[i] = gsl_vector_get(y, i);
}
auto niter = gsl_multifit_nlinear_niter(work);
auto nfev = fdf->nevalf;
auto njev = fdf->nevaldf;
auto naev = fdf->nevalfvv;
// nfev - number of function evaluations
// njev - number of Jacobian evaluations
// naev - number of f_vv evaluations
//logger::debug("curve fitted after ", niter, " iterations {nfev = ", nfev, "} {njev = ", njev, "} {naev = ", naev, "}");
gsl_multifit_nlinear_free(work);
gsl_vector_free(initial_params);
return result;
}
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*
{
auto* result = gsl_vector_alloc(vec.size());
int i = 0;
for(const auto e: vec)
{
gsl_vector_set(result, i, e);
i++;
}
return result;
}
template<typename C1>
struct fit_data
{
const std::vector<double>& t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
template<typename FitData, int n_params>
int internal_f(const gsl_vector* x, void* params, gsl_vector *f)
{
auto* d = static_cast<FitData*>(params);
// Convert the parameter values from gsl_vector (in x) into std::tuple
auto init_args = [x](int index)
{
return gsl_vector_get(x, index);
};
auto parameters = gen_tuple<n_params>(init_args);
// Calculate the error for each...
for (size_t i = 0; i < d->t.size(); ++i)
{
double ti = d->t[i];
double yi = d->y[i];
auto func = [ti, &d](auto ...xs)
{
// call the actual function to be fitted
return d->f(ti, xs...);
};
auto y = std::apply(func, parameters);
gsl_vector_set(f, i, yi - y);
}
return GSL_SUCCESS;
}
using func_f_type = int (*) (const gsl_vector*, void*, gsl_vector*);
using func_df_type = int (*) (const gsl_vector*, void*, gsl_matrix*);
using func_fvv_type = int (*) (const gsl_vector*, const gsl_vector *, void *, gsl_vector *);
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*;
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>;
template<typename C1>
auto curve_fit_impl(func_f_type f, func_df_type df, func_fvv_type fvv, gsl_vector* initial_params, fit_data<C1>& fd) -> std::vector<double>
{
assert(fd.t.size() == fd.y.size());
auto fdf = gsl_multifit_nlinear_fdf();
auto fdf_params = gsl_multifit_nlinear_default_parameters();
fdf.f = f;
fdf.df = df;
fdf.fvv = fvv;
fdf.n = fd.t.size();
fdf.p = initial_params->size;
fdf.params = &fd;
// "This selects the Levenberg-Marquardt algorithm with geodesic acceleration."
fdf_params.trs = gsl_multifit_nlinear_trs_lmaccel;
return internal_solve_system(initial_params, &fdf, &fdf_params);
}
template <typename Callable, auto n>
auto curve_fit(Callable f, const std::array<double, n>& initial_params, const std::vector<double>& x, const std::vector<double>& y) -> std::vector<double>
{
// We can't pass lambdas without convert to std::function.
//constexpr auto n = 3;//decltype(n_params(f))::n_args - 5;
//constexpr auto n = 2;
assert(initial_params.size() == n);
auto params = internal_make_gsl_vector_ptr(initial_params);
auto fd = fit_data<Callable>{x, y, f};
return curve_fit_impl(internal_f<decltype(fd), n>, nullptr, nullptr, params, fd);
}
In order to fix one of the parameters of the gaussian function, #zkoza proposed to use functors:
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(double x, double b, double c) const { return gaussian(x, b, a, c); }
};
And these last lines show how I would create a fake dataset of observed data (with some noise which is normally distributed) and test the fitting curve function with two independent variables, given by the vectors xs and bs.
int main()
{
auto device = std::random_device();
auto gen = std::mt19937(device());
auto xs = linspace<std::vector<double>>(0.0, 1.0, 300);
auto bs = linspace<std::vector<double>>(0.4, 1.4, 300);
auto ys = std::vector<double>(xs.size());
double a = 5.0, c = 0.15;
for(size_t i = 0; i < xs.size(); i++)
{
auto y = gaussian(xs[i], a, bs[i], c);
auto dist = std::normal_distribution(0.0, 0.1 * y);
ys[i] = y + dist(gen);
}
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{0.11}, xs, bs, ys);
std::cout << "result: " << r[0] << ' ' << '\n';
std::cout << "error : " << r[0] - c << '\n';
}
Do you have any idea on how I could implement the two-independent variables non-linear fitting?
The solution, as suggested in the comments by #BenVoigt, is to replace the x and b independent variables in the gaussian function with 'one independent variable' given as a vector, whose first element is x and the second element is b.
Also the backbone of the nonlinear fitting needs to be slightly edited. The edits consist:
Replace the fit_data functor with:
struct fit_data
{
const std::vector< vector<double> > &t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
Such that, the independent variable is no longer a vector but rather a vector of a vector (aka a matrix).
Replace within the function internal_f.
a) double ti = d->t[i] with std::vector<double> ti = d->t[i]
b) auto func = [ti, &d](auto ...xs) with auto func = [ti, &d](auto ...xs_matrix)
c) return d->f(ti, xs...) with return d->f(ti, xs_matrix...)
Replace within curve_fit function:
a) const std::vector<double>& x with const std::vector< vector<double> > &xs_matrix
b) auto fd = fit_data<Callable>{x, y, f} with auto fd = fit_data<Callable>{xs_matrix, y, f}
Whereas the gaussian function, gaussian_fixed_a functor and the fitting function looks like:
double gaussian(std::vector<double> x_vector, double a, double c)
{
const double z = (x_vector[0] - x_vector[1]) / c;
return a * std::exp(-0.5 * z * z);
}
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(std::vector<double> x_vector, double c) const { return gaussian(x_vector, a, c); }
};
double fittingTest(const std::vector< vector<double> > &xs_matrix, const std::vector<double> ys, const double a){
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{3.0}, xs_matrix, ys);
return r[0]);
}

Simplifying external functions calls

I have dozens of such functions, those are calls to some 3rd party external library. Is there any way to simplify it using some modern c++ feature? I want to avoid macros.
class Renderer;
Renderer* pointer;
void DrawSetRedColor(int r) {
using DrawSetRedColor_prototype = void(__thiscall**)(Renderer*, int);
return (*(DrawSetRedColor_prototype)(*(DWORD*)pointer + 0x48))(pointer, r);
}
int DrawLine(int x0, int y0, int x1, int y1) {
using DrawLine_prototype = int(__thiscall**)(Renderer*, int, int, int, int);
return (*(DrawLine_prototype)(*(DWORD*)pointer + 0x4C))(pointer, x0, y0, x1, y1);
}
Something like this would probably work:
template <typename R, typename... Args>
R CallThroughVtable(void* pointer, size_t offset, Args... args) {
using prototype = R (__thiscall**)(void*, Args...);
return (*(prototype)(*(DWORD*)pointer + offset))(pointer, args...);
}
void DrawSetRedColor(int r) {
CallThroughVtable<void>(pointer, 0x48, r);
}
int DrawLine(int x0, int y0, int x1, int y1) {
return CallThroughVtable<int>(pointer, 0x4C, x0, y0, x1, y1);
}

C++ function that can take integer or float or double or any other castable to float

I am trying to implement a Vector3 struct in C++. I am overloading the "*" operator for handling multiplication with the scalar values. So it will work like this:
v1 = Vector3(1.0f, 1.0f, 1.0f);
v2 = 2*v1;
v3 = 2.4f*v1;
v4 = 2.4*v1;
All 3 operations will return a Vector3 instance. However, I don't want to implement 3 functions for this purpose.
Vector3 operator * (int& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (double& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (float& const val) {
return Vector3(x * val, y * val, z * val);
}
Is there a better way of doing this with one function?
Since you are casting all of the types to float again, you don't need that.
If you defined your function to accept a float, then passed an int or any convertible type, it would be cast to float automatically. The following code shows that
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
Vector3 operator*(float val)const{
return Vector3{val * x,val * y,val * z};
}
};
int main(){
Vector3 v1{1,2,3};
auto v2 = v1*2;
std::cout << typeid(v2.x).name();
}
Live
If you want to use the multiplication in reverse order
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
};
Vector3 operator*(float val, const Vector3& v){
return Vector3{val * v.x,val * v.y,val * v.z};
}
int main(){
Vector3 v1{1,2,3};
auto v2 = 2*v1;
std::cout << typeid(v2.x).name();
}
I used public members for simplicity. u may want to use private ones with setters and getters.
If you really must use reference parameters and the float data type internally, and you wish to avoid compiler warnings about implicit conversions, then you can use a templated operator function (note also the modified position of the const qualifier):
template<typename T>
Vector3 operator * (const T& val)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(x * mul, y * mul, z * mul);
}
You will also need to use a Vector3 object as the first operand of the * operator:
int main()
{
Vector3 v1 = Vector3(1.0f, 1.0f, 1.0f);
// Vector3 v2 = 2 * v1;
// Vector3 v3 = 2.4f * v1; // These won't work!
// Vector3 v4 = 2.4 * v1;
Vector3 v2 = v1 * 2;
Vector3 v3 = v1 * 2.4f; // But these will
Vector3 v4 = v1 * 2.4;
return 0;
}
EDIT: If you want a 'commutative' operator (that is, one in which you could use the scalar operand in either position), then you can declare a friend operator that takes two arguments (the constant and a class reference):
template<typename T>
friend Vector3 operator * (const T& val, const Vector3& vec)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(vec.x * mul, vec.y * mul, vec.z * mul);
}
As I see, it's enough to define/declare variant with double and it will work with floats and integers as well.
Here is compilable example (just test & demonstration):
class Vector3 {
public:
Vector3(double x, double y, double z): x(x), y(y), z(z) { }
Vector3 operator * (double val) {
return Vector3(x * val,
y * val,
z * val);
}
private:
double x { 0 };
double y { 0 };
double z { 0 };
};
int main()
{
int a = 1;
float b = 2.1;
double c = 3.5;
Vector3 vec1(1, 2.1f, 3);
Vector3 vec2(a, b, c);
auto vec3 = vec1 * a;
auto vec4 = vec1 * b;
auto vec5 = vec1 * c;
return 0;
}

c++ lambda used but uninitialized

Here is my code, I get the klocworks error
'value' is used uninitialized in this function.
/// Converts rgb to grayscale (in all channels)
template <typename T>
void convert_to_grayscale(rgb_image_s<T> &img)
{
auto r = img[rgb_color_e::red];
auto g = img[rgb_color_e::green];
auto b = img[rgb_color_e::blue];
r.foreach([](T &r, T &g, T &b)
{
/// error: 'value' is used uninitialized in this function.
auto value = reduce_to<T>(0.299 * r + 0.587 * g + 0.114 * b);
r = value;
g = value;
b = value;
}, g, b);
}
reduce_to function
// For integral types T only
template<typename T> // T <- T do nothing
typename std::enable_if<std::is_integral<T>::value, T>::type reduce_to(T t) { return t; }
foreach function
template <class func, typename... types> func&
foreach(func &&f, types&&... images) const
{
// Check that the other input images are at least same size as this is
validate_sizes(images.size()...);
auto skipx = std::initializer_list<int>({ _skip_x, images._skip_x... });
auto all_ones = std::all_of(skipx.begin(), skipx.end(), [](const int skip) { return skip == 1; });
if (all_ones)
{
for (auto y : _height)
{
iterate_row(_width, f, &at(y, 0), &images.at(y, 0)...);
}
}
else
{
for (auto y : _height)
{
iterate_row(_width, f, make_row_iterator(y), images.make_row_iterator(y)...);
}
}
return f;
}
my solution for this is:
/// Converts rgb to grayscale (in all channels)
template <typename T>
void convert_to_grayscale(rgb_image_s<T> &img)
{
auto r = img[rgb_color_e::red];
auto g = img[rgb_color_e::green];
auto b = img[rgb_color_e::blue];
r.foreach([](T &r, T &g, T &b)
{
T value = reduce_to<T>(0.299 * r + 0.587 * g + 0.114 * b); // changed to T instead of auto
r = value;
g = value;
b = value;
}, g, b);
}
I am trying to understand why klocworks thinks this is an error?
Do you think my fix is ok?
I tested it, it looks to be working.

C++ workaround for doubles as template parameters

I know that doubles can't be template parameters so I'm looking for another way to create a function with several parameters. My current (obviously wrong) code looks like this:
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;
}
Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?
What You want here is a policy class which will supply your function with the required values (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 };
};
Your function will only require this policy class (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;
}
Then, the function can be called like this:
sellmeier< SpecificConstants >( 2.0 );
In c++14 you can do the following, shown with one parameter for brevity's sake:
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)
Though it becomes very unfriendly to the caller.
Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?
I don't know if it's a good idea but... yes, I suppose you can wrap your floating points values as static constant inside struct's.
Starting from C++11 (constexpr) you can simply define
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 }; };
pass they as template parameter to sellmeier()
sellmeier<X1, X2, X3, Y1, Y2, Y3>(1.0);
and use the value of types inside sellmeier()
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;
}
Before C++11 (no constexpr available) the syntax, to define the wrapping structs, is a little more annoying: you have to initialize the const value outside of the body of the structs
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;
As I don't need the parameters at compile time I realized a functor is the better/correct solution:
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);
As I don't need the parameters at compile time I realized a functor is the better/correct solution
In this case, if you can use C++11, you can simply write a 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);
}
Starting from C++14, you can simplify (IMHO) as follows
#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);
}