首先,我觉得一定已经有人问过这个问题,但是我所有的搜索都无济于事。如果确实是某处某事的重复,我事先表示歉意。
我正在尝试对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_timing
和end_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...)> f
和auto 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/