简体   繁体   中英

How to manage std::vector of std::function

I'm moving from a class hierarchy for solving ODE to a class to solve a system of ODEs.

In my implementation to work with a single function, I use the following to store my function:

std::function<const Type(const Type, const Type)> numericalFunction

I have a wrapper to evaluate the numerical function:

Type f (Type t, Type u) const noexcept { return numericalFunction(t,u); }

Now I'm moving to solving a system of equations, so I need to store multiple functions. I tried to store the set of functions using a std::vector as given below:

std::vector<std::function<const Type(const Type,const Type)>> numericalFunction;

I want to be able to use the same syntax as used in the above question. That is,

f[0](12,32); should execute numericalFunction.at(0)(12,32);

dfdt[0](t, u); should execute (numericalFunction.at(0)(t, u+eps) - numericalFunction.at(0)(t, u))/eps;

How can I write the code to allow such a syntax?

EDIT I have a problem .. now I need to change the function

std::vector<std::function<const Type(const Type,const Type)>> numericalFunction; 

becames :

std::vector<std::function<const Type(const Type,const std::vector<Type>)>> numericalFunction; 

and the derivative class doesn't works

You can store a collection of functions as:

std::vector<std::function<const Type(const Type t, const Type u)>> numericalFunList;

Your equivalent function to obtain the correct function will be:

const Type f(size_t idx, const Type t, const Type u) { return numericalFunList.at(idx)(t,u); }

The std::vector is internally a dynamic array. This gives each function an index starting from 0 till numericalFunList.size() - 1 . You can identify each function by its index in the vector.


EDIT1:

The OP prefers to use the following syntax: f[0](arg1, arg2);

The above can be easily achieved: numericalFunList[0](1.2, 5.9);

If f is needed for clarity (for mathematicians; programmers would hate it),

auto& f = numericalFunList;
f[0](10.9, 2.4);

As a tip, consider not using f as a variable name globally. If f is the preferred, use auto& f = numericalFunList to do it for you.


EDIT2:

For the new syntax requirements, you need to use two classes each with one operator overload: one to store the set of derivatives with [] operator overloaded and the other to compute the derivative with () operator overloaded.

typedef long double Type;
constexpr Type eps = 1E-12;

using analysisFunction = std::function<const Type(const Type, const Type)>;

class derivatives {
    private:
        class derivative;
    public:
        derivatives(std::vector<analysisFunction>& p_fList) { fList = &p_fList; };
        derivative operator[](int index) {
            return derivative((*fList).at(index));
        }
    private:
        class derivative {
            public:
                derivative(analysisFunction& p_f) { f = &p_f; }
                Type operator()(Type t, Type u) {
                    return (((*f)(t, u + eps)) - ((*f)(t,u)))/eps;
                }
            private:
                analysisFunction *f;
        };
        std::vector<analysisFunction> *fList; //dangling pointer
};

Example usage

int main ()
{
    std::vector <analysisFunction> numericalFunctions;
    auto& f = numericalFunctions;

    f.push_back([](Type t, Type u)->Type { return u*u; });


    std::cout << std::setprecision(16);
    std::cout << f[0](5.0, 10.0) << '\n';

    derivatives dfdt(f);
    std::cout << dfdt[0](5.0, 10.0);
    return 0;
}

Testing code: GeeksForGeeks Online IDE

Note: fList is a dangling pointer. There are several ways to deal with it. You can leave it as it is if you can guarantee that the referenced object wouldn't be deallocated or you can maintain a copy in the object (which would cost memory and CPU).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM