是否有可能制作一个函数包装器来运行注入的代码并返回与注入的函数相同的数据

Is there a possibility to make a function wrapper that runs the injected code and returns the same data as the injected function?

本文关键字:函数 注入 代码 运行 返回 数据 有可能 包装 一个 是否      更新时间:2023-10-16

我玩弄这个想法已经有一段时间了,但似乎无法理解它。

基本上,我想做的是创建一个通用的 Timer 类,该类对所有传递给它的函数进行计时。当多次调用同一函数时对其进行平均,因此它必须以某种方式存储它。因此,它应该使用函数名称来存储任务,并在任务多次发生时对其进行平均。

它应该是什么样子的伪代码。

Class FunctionTaks
{
    std::string d_name;
    double d_execution_time;
}
Class Timer
{
    private:
        std::vector<FunctionTask> d_tasks;
    public:
        template <typename Function, typename ReturnType>
        ReturnType time(Function f)
        {
            // check if function f is timed for first time
            // start timer             
            // run function f
            auto r = f.invoke();
            // stop timer  
            // store function name and time, average if more than once
            // return whatever f should return
            return r;
        }
        void report() const;
}

我真的不知道该怎么做,尤其是当函数 f 具有不同数量的参数时。

Timer t;
t.time(foo());
t.time(bar());
t.time(foo());
t.report();

我基本上有几个核心问题。

  1. 如何让函数包装器返回与注入的代码假定返回的相同类型。
  2. 如何获取正在注入的函数名称。
  3. 包装器不应受到传递给注入函数的参数的限制。如何赋予注入函数参数的自由。

另一方面,我并不真正关心参数和返回类型,包装器应该简单地按原样运行注入的函数并执行一些计时,然后返回注入的函数应该返回的任何内容。

C++11 但为什么是模板?您需要 lambda 表达式:

typedef void(*TimerFunction)();
void time(TimerFunction fun) {
    // start timer
    fun();
    // stop timer
}
int fun1() { return 1; }
int fun2() { return 2; }
string fun3() { return string("Test"); }
main() {
    int ret1, ret2;
    string ret3;
    t.time([&ret1]() { ret1 = fun1(); });
    t.time([&ret2]() { ret2 = fun2(); });
    t.time([&ret3]() { ret3 = fun3(); });
}

这就是概念。有关详细信息:C++ lambda 将捕获作为函数指针

使用 C++11,您可以使用变量模板参数:

class TimerFoo {
public:
   template <class Foo, class... Args> TimerFoo(Foo foo, Args... args) {
      // ... start timer
      foo(args...);
      // ... stop timer
   }
};

并使用例如:

TimerFoo tf = TimerFoo(foo, 1, 2, 3);

当然,您需要TimerFoo中的一些字段来存储测量的时间...

编辑:

为了能够使用此方法返回函数的值,您可以将上面的代码更改为:

#include <iostream>
using namespace std;
class TimerFoo {
public:
   template <class Foo, class... Args> auto run(Foo foo, Args... args) -> decltype(foo(args...)) {
      // ... start timer
      auto result = foo(args...);
      // ... stop timer
      return result;
   }
};

int foo(int a, int b) {
   return 2;
}
int main() {
   TimerFoo tf;
   cout << tf.run(foo, 1, 2) << endl; // output: 2
}