I'm using ROOT Cern to solve a multi-variable non-linear system of equations. For some problems I have 4 functions and 4 variables. However, for others I need 20 functions with 20 variables. I'm using a class called "WrappedParamFunction" to wrap the functions and then I add the wrapped functions to the "GSLMultiRootFinder" to solve them. The function is wrapped this way:
ROOT::Math::WrappedParamFunction<> g0(&f0, "number of variables", "number of parameters");
Therefore, I need to declare the f0...fi functions before my void main(){}
part of the code. I'm declaring the functions in this way:
double f0(const double *x, const double *par){return -par[0] y[0]*par[1];}
double f1(const double *x, const double *par){return -par[1] y[1]*par[2];}
.
.
Is there a way to create those functions inside a loop and stack them in an array? Something like this:
double (*f[20])(const double *x, const double *par);
for(int i=0;i<20;i ){
f[i]= -par[i] x[i]*par[i 1];
}
So that later I can wrap the functions in this way:
ROOT::Math::WrappedParamFunction<> g0(f[0], "number of variables", "number of parameters");
CodePudding user response:
f[i]= -par[i] x[i]*par[i 1];
You can't generate code at runtime, so you can't do exactly what you're asking for.
You can however save the value of i
for use at runtime, so you have a single callable object with a hidden parameter i
not passed explicitly by the caller. The simplest example is
auto f = [i](const double *x, const double *par)
{
return -par[i] x[i]*par[i 1];
};
but this gives a unique type to the lambda f
, so you can't easily have an array of them.
You can however write
using Callable = std::function<double, const double *, const double *>;
std::array<Callable, 20> f;
and store the lambdas in that.
I think you'll need to use ROOT::Math::WrappedParamFunction<Callable>
for this to work, though, since the FuncPtr
parameter type is not erased.
If you really can't change the WrappedParamFunction
type parameter for whatever reason, you can generate a free function instead of a stateful lambda using templates - but it's pretty ugly.
Edit - I was considering writing that version out too, but fabian beat me to it. Do note that you have to either write out all that machinery for each distinct function that needs this treatment, wrap it in a macro, or generalize everything to take a function template parameter as well.
CodePudding user response:
There are almost certainly better ways of accomplishing this, but this probably gets you closest to the desired result described in the question:
Create a function template with the offset as template parameter and then create an std::array
of function pointers with function pointers pointing to specializations of a template function. Note that the size of the array must be a compile time constant for this to work:
template<size_t Offset>
double f(const double* y, const double* par)
{
return -par[Offset] y[Offset] * par[Offset 1];
}
template<size_t ... Offsets>
std::array<double(*)(double const*, double const*), sizeof...(Offsets)> CreateFsHelper(std::index_sequence<Offsets...>)
{
return { &f<Offsets>... };
}
template<size_t N>
std::array<double(*)(double const*, double const*), N> CreateFs()
{
return CreateFsHelper(std::make_index_sequence<N>{});
}
int main()
{
auto functions = CreateFs<20>();
}
CodePudding user response:
"Is there a way to create an array of functions inside a loop in C or C "
sure, you can create a std::array
or std::vector
of std::function
.
You can also create a container of function pointers if you so desire.
CodePudding user response:
Making your i a template parameter and generating the functions recursively at compile time can also do the trick:
using FunctionPrototype = double(*)(const double *, const double *);
template<int i>
double func(const double * x, const double * par) {
return -par[i] x[i]*par[i 1];
}
template<int i>
void generate_rec(FunctionPrototype f[]) {
f[i-1] = &func<i-1>;
generate_rec<i-1>(f);
}
template<>
void generate_rec<0>(FunctionPrototype f[]) { }
template<int i>
FunctionPrototype* generate_functions()
{
FunctionPrototype * f = new FunctionPrototype[i]();
generate_rec<i>(f);
return f;
}
FunctionPrototype * myFuncs = generate_functions<3>(); // myFuncs is now an array of 3 functions