【问题标题】:How to wrap a function to fit the required type of another function如何包装一个函数以适应另一个函数的所需类型
【发布时间】:2020-01-28 07:29:35
【问题描述】:

考虑以下三个函数:

using phase_t = Eigen::VectorXd;
using rhs_t = phase_t (*)(double const &, phase_t const &);
using step_t = phase_t (*)(rhs_t , phase_t const &, double, double);

Eigen::MatrixXd foo_ee_step(rhs_t rhs, phase_t const &z0);
Eigen::MatrixXd foo_int(step_t step, rhs_t rhs, phase_t const & z0);
Eigen::MatrixXd foo_ee(rhs_t rhs, phase_t const &z0);

它们都有一个rhs_t 类型的参数,我在上面的第二行中指定了它。此外,其中一个函数具有step_t 类型的参数,该参数取决于rhs_t 类型的参数。我的问题是我想传递给foo_ee_stepfoo_intfoo_ee 的变量来自

phase_t my_rhs(double const &, phase_t const &, double);

由于我无法更改 foo_ee_stepfoo_intfoo_ee,我尝试使用 lambda 以合适的方式重新定义函数

Eigen::MatrixXd some_function(.....):
    auto better_rhs = [&c](double const & a, phase_t const & b){return my_rhs(a,b,c);};
    return foo_ee(better_rhs, m);

但这会导致

error: cannot convert ‘some_function(....)::<lambda(const double&, const phase_t&)>’ to ‘rhs_t’ {aka ‘Eigen::Matrix<double, -1, 1> (*)(const double&, const Eigen::Matrix<double, -1, 1>&)’}

我认为这是因为我试图传递一个捕获某些东西作为函数指针的 lambda,这似乎是 forbidden...我读过 here,可以尝试通过定义函子来解决这个问题。但如果我没记错的话,我需要更改foo_ee_stepfoo_intfoo_ee,但我不能……所以,我真的不知道如何解决这个问题。 . 是否有可能以某种方式将此 lambda 表达式转换为rhs_t 的形式?有没有其他技术可以解决这个问题?

附:不确定它是否重要,但到目前为止我也尝试过:

  1. some_function 中定义另一个名为 better_rhs 的函数(显然也没有工作)。
  2. 将所有这些包装到一个类中,并使用foo_ee_step 等作为成员函数。然后只需定义另一个成员函数better_rhs 并在那里调用my_rhs.. 这导致无法传递非静态成员函数但必须显式调用它的错误......

感谢任何有关如何进行的提示。

【问题讨论】:

    标签: c++ function pointers


    【解决方案1】:

    做到这一点的唯一方法是非常老套。您必须意识到函数指针只是指向函数所在的静态内存位置的指针。因此,不可能添加具有动态或自动存储持续时间(堆或堆栈数据)的状态(即绑定额外的双参数)。该功能现在需要它所在的位置,但它不能。 (这就是为什么 C 中的泛型函数接口采用 void* 而函数指针也采用 void* 的原因,因此状态位置作为指向 void 的指针传递,然后在函数中解释为正确的类型)

    您可以添加具有静态存储持续时间的状态,即通过以下方式:

    // Interface we want to match
    void print_call(int (*f)()) {
      std::cout << f() << `\n`;
    }
    // Way 1: Globals
    static int data = 0;
    int get_data() { return data; } 
    
    print_call(get_data); // Prints 0
    data = 42;
    print_call(get_data);  // Prints 42
    
    // Way 2: Class statics
    struct state {
      int data = 0;
      static int get_data() { return data; }
    };
    
    print_call(state::get_data); // Prints 0
    state::data = 42;
    print_call(state::get_data); // Prints 42
    

    出于封装和更易于理解的初始化顺序的原因,我更喜欢方式 2。

    请注意,使用静态有其自身的问题。你可能想看看你是否不能以某种方式改变你的设计来摆脱整个问题。

    【讨论】:

      【解决方案2】:

      通常采用函数指针的外部函数也采用void* 数据指针,因此可以传递额外的上下文(在您的情况下是指向双精度的指针)。没有它,函数就没有足够的数据被调用。

      您可以尝试静态双精度:

      static double data;
      data = c;
      return foo_ee([](double const& a, phase_t const& b) { return my_rhs(a, b, data); }, m);
      

      但这不是线程安全的(而且我不知道如何调用传递的函数,但第二次运行会使旧函数指针指向新数据,可能不是你想要的)。

      也许phase_t 里面有那个上下文指针?

      【讨论】:

        【解决方案3】:

        您可以将 c 存储在一个全局变量中,或者存储在某个 get_global_c 函数中的静态变量中,并在您的 lambda 中引用它,这样您就不必捕获它:

        // ...
        static double c;
        void some_function()
        {
            // ...
            c = calculate_c();
            auto better_rhs = [](double const &a, phase_t const &b) { return my_rhs(a, b, c); };
            rerturn foo_ee(better_rhs, m);
        }
        

        【讨论】:

          猜你喜欢
          • 2013-05-23
          • 1970-01-01
          • 2020-11-22
          • 1970-01-01
          • 2021-03-26
          • 2022-11-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多