std::function有模板,类型问题,没有匹配的调用函数

std::function with template, type problem, no matching function for call

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

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;

给"function"的类型是:

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

而且我也不能使用 "function" 作为 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 无法识别 "right" 类型?

谢谢:)

您收到 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);

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

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

#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;
}

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

由于传递 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(...);

的东西