Search code examples
c++templatestypesautostd-function

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


I have a function defined this way:

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

and another function, which should be the argument of the previous, defined like this:

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

If I try to call "MyFun" like this:

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

I get this error:

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>&)’

Moreover, if I try to store "MyFun2" in a variable with "auto"

  auto function = MyFun2;

the type given to "function" is:

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

and I can't use "function" as a parameter for MyFun aswell. The only solution I've found is to somewhat cast "MyFun2" in the right type by specifying it:

  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);

This way, passing "function" as the first parameter of "MyFun" works. But why do I have such an ambiguity and I can't call MyFun by just typing MyFun2 as the first parameter? And why auto won't figure out the "right" type?

Thank you :)


Solution

  • You're getting the no matching function for call to... error std::function doesn't have deduction guides for deducing the signature of a function pointer.

    When you do this:

    auto function = MyFun2;
    

    The function, MyFun2 is decayed to a function pointer. It doesn't make sense to store the value of a function in a variable because, well, what is the value of a function? It's a block of machine instructions. Why would you ever want to copy that around? The language assumes that you won't so a function is decayed to a function pointer. The above is equivalent to this:

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

    You found one solution to the error and that is to construct a std::function from the function pointer directly. Another solution would be to avoid std::function altogether.

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

    So now your original example works

    something = MyFun(MyFun2, var, var2);