【问题标题】:std::function with template, type problem, no matching function for call带有模板的 std::function,类型问题,没有匹配的调用函数
【发布时间】:2019-12-01 10:03:32
【问题描述】:

我有一个这样定义的函数:

template <size_t SIZE>
double MyFun(std::function<double(std::array<double,SIZE>&)> f, std::array<double,SIZE> &x, std::array<double,SIZE> &y){
   instructions;
}

另一个函数,应该是前一个的参数,定义如下:

double MyFun2(std::array<double,3> &var){
  instructions;
}

如果我尝试这样称呼“MyFun”:

    double something;
    std::array<double,3> var = {...};
    std::array<double,3> var2 = {...};
    something = MyFun(MyFun2, var, var2);

我得到这个错误:

error: no matching function for call to ‘MyFun(double (&)(std::array<double, 3>&), std::array<double, 3>&, std::array<double, 3>&)’
note:   template argument deduction/substitution failed:
note:   mismatched types ‘std::function<double(std::array<double, SIZE>&)>’ and ‘double (*)(std::array<double, 3>&)’

此外,如果我尝试将“MyFun2”存储在带有“auto”的变量中

  auto function = MyFun2;

赋予“函数”的类型是:

  double (*function)(std::array<double, 3UL> &var)

我也不能使用“函数”作为 MyFun 的参数。 我发现的唯一解决方案是通过指定将“MyFun2”转换为正确的类型:

  double something;
  std::array<double,3> var = {...};
  std::array<double,3> var2 = {...};

  std::function<double(std::array<double,3>&)> function = MyFun2;
  something = MyFun(function, var, var2);

这样,将“function”作为“MyFun”的第一个参数传递就可以了。 但是为什么我有这样的歧义,我不能只通过输入 MyFun2 作为第一个参数来调用 MyFun?为什么 auto 不能找出“正确”的类型?

谢谢你:)

【问题讨论】:

    标签: c++ templates types auto std-function


    【解决方案1】:

    模板参数推导通过精确匹配您传入的参数来工作。它不考虑转换。

    由于传递MyFun 与传递函数指针相同,并且您的模板正在寻找std::function,因此推导失败。

    惯用的方法是接受模板中的任何可调用对象,而不用担心签名。由于您将在模板中调用该可调用对象,因此如果签名不匹配,无论如何您都会收到编译时错误。

    template <typename Func, size_t SIZE>
    double MyFun(F f, std::array<double,SIZE> &x, std::array<double,SIZE> &y){
       // go ahead and use f(x, y); for example
    }
    

    这种方法还有一个额外的好处,那就是您不限于一种类型的可调用对象。我们可以传入一个函数指针、一个 std::function、一个 Functor。任何支持语法f(...);

    【讨论】:

      【解决方案2】:

      要创建std::function 的对象,您需要使用std::bind(&amp;MyFun2, std::placeholders::_1)。供参考address cppreference 。

      您的代码也存在一些问题。 std::funcion 相当大,在 x64 中会占用 64 个字节,所以复制它不是最好的解决方案。您可以将其作为 const 引用传递,也可以作为 r 值引用传递给 RAII。

      #include <array>
      #include <iostream>
      #include <functional>
      
      #include <numeric>
      
      // typedef Alias for convinence
      template <size_t sz>
      using Wrapped_t = std::function<double(const std::array<double, sz>&)>;
      
      template <size_t sz>
      double MyFunc(const Wrapped_t<sz> &f, const std::array<double, sz> &arr1, const std::array<double, sz> &arr2)
      {
          // some dummy implementation for demonstratio purposes 
          return f(arr1) + f(arr2);
      }
      
      double MyFunc2(const std::array<double, 3> &arr)
      {
          // some dummy implementation for demonstratio purposes 
          return std::accumulate(arr.cbegin(), arr.cend(), 0);
      }
      
      int main()
      {
          std::cout << sizeof(Wrapped_t<3>) << std::endl;     // 64 bytes for x64 build. You are better off not copying your function object
      
      
          std::cout << MyFunc2({ 3.14, 2.18, 2.895 }) << std::endl; // invoking your function as regular
      
          // to create an std::function object you should use std::bind
          Wrapped_t<3> wrapped = std::bind(&MyFunc2, std::placeholders::_1);
          std::cout << wrapped({ 3.14, 2.18, 2.895 }) << std::endl; // invoking your function wrapped to std::function
      
          std::array<double, 3> arr1{ 3, 14, 28 },
              arr2{ 2, 18,9 };
      
          // this is what you asked for
          std::cout << MyFunc(wrapped, arr1, arr2) << std::endl;
      
      
          return 0;
      }
      
      

      【讨论】:

      • 也谢谢你,我很欣赏性能的观点! :)
      【解决方案3】:

      您收到no matching function for call to... 错误std::function 没有用于推断函数指针签名的推断指南。

      当你这样做时:

      auto function = MyFun2;
      

      函数MyFun2 衰减为函数指针。将函数的值存储在变量中是没有意义的,因为,函数的值是什么?这是一个机器指令块。你为什么要复制它?该语言假定您不会,因此函数会衰减为函数指针。以上等价于:

      double (*function)(std::array<double, 3> &var) = MyFun2;
      

      您找到了一种解决该错误的方法,即直接从函数指针构造一个std::function。另一种解决方案是完全避免使用std::function。

      template <size_t SIZE>
      double MyFun(double (*f)(std::array<double, SIZE>&), std::array<double, SIZE> &x, std::array<double, SIZE> &y){
         instructions;
      }
      

      所以现在你原来的例子可以工作了

      something = MyFun(MyFun2, var, var2);
      

      【讨论】:

      • 感谢您花时间解释!我明白了这个问题!在这种情况下,我将使用函数指针 :)
      猜你喜欢
      • 2011-03-03
      • 1970-01-01
      • 2013-01-26
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多