【问题标题】:How to manage std::vector of std::function如何管理 std::function 的 std::vector
【发布时间】:2018-05-26 03:28:20
【问题描述】:

我正在从用于求解 ODE 的类层次结构转移到用于求解 ODE 系统的类。

在我使用单个函数的实现中,我使用以下内容来存储我的函数:

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

我有一个包装器来评估数值函数:

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

现在我要解决方程组,所以我需要存储多个函数。我尝试使用std::vector 存储函数集,如下所示:

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

我希望能够使用与上述问题相同的语法。也就是说,

f[0](12,32); 应该执行numericalFunction.at(0)(12,32);

dfdt[0](t, u); 应该执行(numericalFunction.at(0)(t, u+eps) - numericalFunction.at(0)(t, u))/eps;

如何编写代码来允许这样的语法?

编辑我有问题..现在我需要更改功能

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

变成了:

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

派生类不起作用

【问题讨论】:

  • return numericalFunction.at(0)(t,u); 没有意义,numericalFunctionstd::function
  • Type f (size_t function_id, Type t, Type u) const noexcept { numericalFunction.at(function)(t,u); } 这样可以吗?正如@YSC 所说,at 不是std::function 的成员函数。
  • 说实话,我不知道你在问什么
  • auto numFun1 = [](double t , double u) {return -20*u+20*sin(t)+cos(t) ; } ; 不应该是auto numFun1 = [](double t , double u)-&gt;double {return -20*u+20*sin(t)+cos(t) ; } ;
  • 你想如何选择一个函数?该函数是否被赋予了唯一的 ID?如果是,是否从 0 开始,是否连续?

标签: c++ class vector operator-overloading


【解决方案1】:

您可以将函数集合存储为:

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

获得正确函数的等效函数是:

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

std::vector 在内部是一个动态数组。这为每个函数提供了一个从0numericalFunList.size() - 1 的索引。您可以通过向量中的索引来识别每个函数。


EDIT1:

OP 更喜欢使用以下语法:f[0](arg1, arg2);

以上可以轻松实现:numericalFunList[0](1.2, 5.9);

如果为了清楚起见需要f(对于数学家;程序员会讨厌它),

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

作为提示,请考虑不要将f 用作全局变量名。如果f 是首选,请使用auto&amp; f = numericalFunList 为您完成。


EDIT2:

对于新的语法要求,您需要使用两个类,每个类都具有一个运算符重载:一个用于存储具有[] 运算符重载的导数集,另一个用于计算具有() 运算符重载的导数。

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
};

使用示例

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;
}

测试代码:GeeksForGeeks Online IDE

注意:fList 是一个悬空指针。有几种方法可以处理它。如果您可以保证引用的对象不会被释放,或者您可以在对象中维护一个副本(这会消耗内存和 CPU),则可以保持原样。

【讨论】:

  • 是的,使用地图可能比在参数中使用 id 更好!如何设置地图?
  • 您能否在问题中提供有关您的密钥的更多信息?请注意,std::map 通常以树的形式实现,并且会为您提供 O(log n) 的搜索复杂度,而 std::unordered_map 以哈希图的形式实现的平均复杂度为 O(1)。
  • 相邻数严格加一吗?是1, 2, 3, 4, 5 还是3, 7, 9, 12, 13, 14
  • adiacent 基本上我只需要在要调用的函数的键和索引之间建立连贯性
  • 那么 std::vector 就是你的容器。它会为您提供恒定的时间查找,但它会要求您的号码从 0 开始,并且对于每个相邻的号码对严格增加一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多