Reputation: 2620
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:
operator%
which uses two function<int(int)>
parameters andoperator*
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
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
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,
use function instead of operator, such as
template<typename T>
function<int(int)> multi(T x, T y)
declare one of the function parameter as `function
template<typename T>
function<int(int)> operator*(function<int(int)> x, T y)
Upvotes: 2