Igor Popov
Igor Popov

Reputation: 2620

Binding of regular function to std::function

I am trying to code a functional composition using operator overloading in C++, so to have a simple composition syntax similar to the ones in functional languages (e.g. Haskell). My aim is to use regular bare C++ functions in the composition. There are two overloads which I coded so far:

  1. operator% which uses two function<int(int)> parameters and
  2. operator* which uses template type as parameters.

operator% works well, but in main() I have firstly to wrap regular functions into function<int(int)> in order operator% to accept them as input parameters. I want to avoid this additional step by migrating it into overloaded operator* which uses template parameters. I thought that it is possible to bind regular functions to the template parameters of operator*, but compiler reports the error:

composingFunc.cpp11.cpp: In function ‘int main()’:
composingFunc.cpp11.cpp:28:12: error: invalid operands of types ‘int(int)’ and ‘int(int)’ to binary ‘operator*’
   cout<<(f*g)(5)<<endl;

Do you have any idea how to solve this issue? Using template parameters in operator*is not mandatory - if you have some other approach simply suggest here.

Here is the source code:

#include<iostream>
#include<functional>

using namespace std;

int f(int n)
{  return 2*n; }

int g(int n)
{  return n+1; }

function<int(int)> operator%(function<int(int)> f, function<int(int)> g)
{ 
  return [=](int x){ return f(g(x));};
}

template<typename T>
function<int(int)> operator*(const T &f, const T &g)
{
  function<int(int)> f1=f,f2=g; //this is encapsulated here so it is not
                                //necessary to repeat the same in main 
                                //for every functional composition
  return [=](int x){ return f1(f2(x));};
}

int main()
{
  function<int(int)> f1=f, f2=g; //I want to encapsulate this step into operator*
  cout<<(f1%f2)(5)<<endl; //this works well
  cout<<(f*g)(5)<<endl; //error in this line
}

EDIT: Solution given by Zac uses a class type for one of function arguments (it is mandatory, by the standard, to use at least one enum or class type argument in operator overloads) and a template type argument. Then regular C++ functions gladly bind to both arguments. Thus the final operator overload is quite simple:

template<typename T>
function<int(int)> operator*(function<int(int)> f, T g)
{
    return [=](int x){ return f(g(x));};
}

and regular functions can be composed then using simple (f*g)(x) syntax.

Upvotes: 2

Views: 324

Answers (2)

Daniel Frey
Daniel Frey

Reputation: 56903

The only idea that comes to mind is to start with some dummy:

struct F{}F;

function<int(int)> operator*(struct F, function<int(int)> g)
{
    return g;
}

function<int(int)> operator*(function<int(int)> f, function<int(int)> g)
{
    return [=](int x){ return f(g(x));};
}

int main()
{
    cout<<(F*f*g)(5)<<endl; // start with F, then add the real stuff
}

Upvotes: 3

Zac Wrangler
Zac Wrangler

Reputation: 1445

As Daniel pointed out, one of the argument in the operator overload has to be class or enumerated type. Therefore the call to f*g needs to be instantiated to function<int(int)> instead of function pointer type. There are two options for this problem,

  1. use function instead of operator, such as

    template<typename T>
    function<int(int)> multi(T x, T y)
    
  2. declare one of the function parameter as `function

    template<typename T>
    function<int(int)> operator*(function<int(int)> x, T y)
    

Upvotes: 2

Related Questions