0

basically I want to integrate a multi-dimensional integral with this recursion.
But the problem itself is a general one. It's not specific for integration.

#include "math.h"
#include <iostream>
#include <functional>

double f(double x,double y,double z){
    return x+y+z+1;
}

//Base
double redDim(std::function<double(double)> &f){
    return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
    return redDim([=](Trest... R){return redDim([=](double x){return f(x,R...);});});
}

int main(){
    std::cout<<redDim(f)<<std::endl;
    return 0;
}

The problem is, compiler says:

c:\C++\templateTutorial\templateTut.cpp: In function 'int main()':
c:\C++\templateTutorial\templateTut.cpp:24:19: error: no matching function for call to 'redDim(double (&)(double, double, double))'
     cout<<redDim(f)<<endl;
                   ^
c:\C++\templateTutorial\templateTut.cpp:12:8: note: candidate: 'double redDim(std::function<double(double)>&)'
 double redDim(std::function<double(double)> &f){
        ^~~~~~
c:\C++\templateTutorial\templateTut.cpp:12:8: note:   no known conversion for argument 1 from 'double(double, double, double)' to 'std::function<double(double)>&'
c:\C++\templateTutorial\templateTut.cpp:17:6: note: candidate: 'template<class Tfirst, class ... Trest> auto redDim(std::function<double(Tfirst, Trest ...)>&)'
 auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
      ^~~~~~
c:\C++\templateTutorial\templateTut.cpp:17:6: note:   template argument deduction/substitution failed:
c:\C++\templateTutorial\templateTut.cpp:24:19: note:   mismatched types 'std::function<double(Tfirst, Trest ...)>' and 'double(double, double, double)'
     cout<<redDim(f)<<endl;
                   ^
The terminal process terminated with exit code: 1

So why is the type of f not matching the requirements of redDim() ?
Thus I can't even test, if my method works.
I hope you could help me!

Babalion
  • 5
  • 3
  • Does this answer your question? [Lambda of a lambda : the function is not captured](https://stackoverflow.com/questions/13461538/lambda-of-a-lambda-the-function-is-not-captured) – walnut Jan 25 '20 at 22:05

2 Answers2

0

A function pointer is not a std::function.

Template argument deduction does not do any type conversions, other than a few to-base cases.

Add a redim( double(*f)(Args...) ) template that calls the std function one.

template<class...Args>
auto redDim( double(*f)(Args...) {
  return redDim( std::function<double(Args...)>{ f } );
}

and it should work.

This can deduce the signature of the function pointer. It then explicitly converts to a std::function, which then matches your other redim functions.

You do have to explicitly convert your other lambdas to std::functions:

// Recursion
template<typename Tfirst, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> f){
  return redDim(
    std::function<double(Trest...)>{
      [=](Trest... R){
        return redDim(
          std::function<double(double)>{
            [=](double x){return f(x,R...);}
          }
        );
      }
    }
  );
}

Live example.

Also change the argument for the last redDim to std::function<double(double)> (not a reference). Alternatively, a const&.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Now the next error is: required from 'auto redDim(double (*)(Args ...)) [with Args = {double, double, double}]' **error:** no matching function for call to 'redDim(redDim(std::function) [with Tfirst = double; Trest = {double, double}]::)' return redDim([&](Trest... rest){return redDim([&](double x){return f(x,rest...);});}); – Babalion Jan 26 '20 at 20:10
  • @Babalion Live example added. – Yakk - Adam Nevraumont Jan 27 '20 at 18:19
0

Based on Yakk - Adam Nevraumont's answer, the following code should compile:

#include "math.h"
#include <iostream>
#include <functional>

double f(double x,double y,double z){
    return x+y+z+1;
}

//Base
double redDim(const std::function<double(double)> &f){
    return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(const std::function<double(Tfirst first,Trest... rest)> &f) {

    return redDim(
    std::function<double(Trest...)>{
        [=](Trest... R)->double{return redDim([=](double x){return f(x,R...);});}});
}

template<class...Args>
auto redDim( double(*f)(Args...)) {
  return redDim( std::function<double(Args...)>{ f } );
}

int main(){
    std::cout<<redDim(f)<<std::endl;
    return 0;
}

As Yakk already pointed out, std::function and a function pointer don't have the same type. Please note that I've also changed the argument type of redDim to const std::function<...> &). You could also pass rvalue references using the && syntax.

StefanKssmr
  • 1,196
  • 9
  • 16