首先,我觉得一定已经有人问过这个问题,但是我所有的搜索都无济于事。如果确实是某处某事的重复,我事先表示歉意。
我正在尝试对OpenCV的一系列功能进行基准测试,为此,我想编写一个小型的元功能,该功能可以运行该功能,其参数(根据传递的功能而有所不同),并实质上设置了计时并循环运行该函数。
由于我计划稍后再将lambda传递给元函数(以对函数的基准进行基准测试),因此我想到了使用std::function
这是我阅读the parameter pack description之后想到的代码:

template<typename ...Ts>
void run_test(std::string test_name, int num_repeats, std::function<void(Ts...)> f, Ts... fargs)
{
    std::cout << std::endl << "Starting " << test_name << std::endl;
    start_timing(test_name);
    for(int i=0; i<num_repeats; i++)
    {
        f(fargs...);
    }
    end_timing(num_repeats);
}
如您所见,功能降到最低。 start_timingend_timing是简单的辅助函数,超出了本问题的范围。
我主要是这样称呼的:
// im_in defined and loaded elsewhere
cv::Mat out(im_in.size(), CV_8U);
run_test(
    "erode 3x3",
    100,
    cv::erode,
    im_in, out, cv::Mat::ones(3,3,CV_8U)
);
现在,如果我尝试对此进行编译,则会得到:
error: no matching function for call to 'run_test(const char [10], const int&, void (&)(cv::InputArray, cv::OutputArray, cv::InputArray, cv::Point, int, int, const Scalar&), cv::Mat&, cv::Mat&, cv::MatExpr)'
  );
  ^
note: candidate: template<class ... Ts> void run_test(std::__cxx11::string, int, std::function<void(Ts ...)>, Ts ...)
 void run_test(std::string test_name, int num_repeats, std::function<void(Ts...)> f, Ts... fargs)
      ^~~~~~~~
note:   template argument deduction/substitution failed:
note:   mismatched types 'std::function<void(Ts ...)>' and 'void (*)(cv::InputArray, cv::OutputArray, cv::InputArray, cv::Point, int, int, const Scalar&) {aka void (*)(const cv::_InputArray&, const cv::_OutputArray&, const cv::_InputArray&, cv::Point_<int>, int, int, const cv::Scalar_<double>&)}'
  );
所以...我在做什么错?为什么它的类型不匹配,而不是像我期望的那样从参数列表中推导Ts...中的类型?

更新:
在写完上面的最后一个问题之后,我意识到推导Ts...std::function可能会有问题,因为该参数在实际参数列表之前扩展为Ts...。因此,我如下更改了代码(本质上,我在最后移动了f参数):
void run_test(std::string test_name, int num_repeats, Ts... fargs, std::function<void(Ts...)> f)
{ ... }
当然,我也相应地修改了函数调用:
cv::Mat out(im_in.size(), CV_8U);
run_test(
    "erode 3x3",
    NUM_REPEATS,
    im_in, out, cv::Mat::ones(3,3,CV_8U),
    cv::erode, // <<<<<<<<<<<<<<<<<<<<<<<
);
现在,如果我进行编译,则会收到另一个错误:
error: expected primary-expression before ')' token );
误差的变化使我认为参数的顺序确实很重要。但是,这是正确的吗?如果是这样,我在做什么错?

更新2:
在编写第一个更新时,令我震惊的是,我对f可以接受一个函数并将其转换为std::function的假设可能是错误的。经过快速研究,看来确实如此。
我尝试用std::function<void(Ts...)> fauto f替换auto& f(&启用C++ 14编译),但是expected primary-expression错误仍然存​​在。
就我所能进行的研究而言,我找不到一种方法可以允许我仅依靠编译器来传递函数来确定类型。
我正在考虑改用here所示的C++ 17的std::apply函数实现,在invoke调用周围添加我的计时循环,但是我不理解该代码,因此出错的可能性很高。

最佳答案

您可能会摆脱std::function(这会增加开销的BTW),并且也将genet用于f:

template<typename F, typename ...Ts>
void run_test(std::string test_name, int num_repeats, F f, const Ts&... fargs)
{
    std::cout << std::endl << "Starting " << test_name << std::endl;
    start_timing(test_name);
    for(int i=0; i<num_repeats; i++)
    {
        f(fargs...);
    }
    end_timing(num_repeats);
}



由于cv::erode不是std::function,因此无法从中推导Ts...,但可以从其他参数推导得出。

您的问题是cv::erode具有额外的(默认)参数。
因此您无法使用从参数推导出的std::function<Ts...>创建Ts...

要绕过该问题,您可以改用lambda:
run_test(
    "erode 3x3",
    100,
    [&](){ cv::erode(im_in, out, cv::Mat::ones(3,3,CV_8U)); }
);

关于c++ - 将通用函数及其参数传递给元函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50860714/

10-11 22:09
查看更多