代码之家  ›  专栏  ›  技术社区  ›  GPhilo satyendra

将泛型函数及其参数传递给元函数

c++
  •  1
  • GPhilo satyendra  · 技术社区  · 7 年前

    首先,我觉得这件事肯定已经有人问过了,但我所有的调查都没有结果。如果这确实是某个地方的复制品,我提前道歉。

    我正在尝试对opencv中的一组函数进行大规模基准测试,为此我想编写一个小的元函数,它接受要运行的函数,其参数(根据传递的函数而变化)并基本上设置计时并循环运行该函数。

    由于我计划稍后也将lambdas传递给元函数(以对函数的组合进行基准测试),所以我考虑使用 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::功能 因为参数位于要展开到的实际参数列表之前 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::功能 可能是错的。经过快速的研究,似乎是这样。

    我试着替换 std::function<void(Ts...)> f 两者兼有 auto f auto& f (与C++ 14启用编译),但 expected primary-expression 错误仍然存在。

    尽管我已经做了很多研究,但我还是找不到一种方法可以让我通过依赖编译器来计算类型的函数。 我想适应C++ 17的 std::apply 显示的功能实现 here 添加我的计时循环 invoke 打电话来,但我不明白代码,所以出错的几率很高。

    2 回复  |  直到 7 年前
        1
  •  4
  •   Jarod42    7 年前

    你也许可以摆脱 std::function (这增加了间接BTW),并使用泛型 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);
    }
    

    我意识到可能在推断…对于STD::函数

    AS cv::erode 不是一个 STD::功能 , Ts... 无法从中推断,但将从其他参数中推断。

    你的问题是 简历:侵蚀 有额外(默认)参数。 所以你不能创建 std::function<Ts...> 具有 Ts.… 从参数推断。

    要绕过此问题,可以使用lambda代替:

    run_test(
        "erode 3x3",
        100,
        [&](){ cv::erode(im_in, out, cv::Mat::ones(3,3,CV_8U)); }
    );
    
        2
  •  3
  •   Tyker    7 年前

    误差 expected primary-expression before ')' 是因为你留下了 , 在最后一个参数之后

    参数包必须始终是函数的最后一个参数

    你应该试试这个

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