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 and
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.
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
}
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)
Related
I'm trying to create a function template which accepts std::max and others with compatible prototypes:
template <typename F>
int f(F g)
{
return g(1,2);
}
Because of the many overloads, the template argument F cannot be inferred f.e. for std::max, so this will fail:
f(std::max);
One possibility is to hint with a static_cast:
f(static_cast<int const& (*)(int const&,int const&)>(std::max));
I'm looking for a less verbose way while still being able to also easily pass any other sort of matching function, like f.e.
f([](int i, int j) { return 3; });
f(std::function<int(int,int)>([](int i, int j) { return 4; }));
Here's a godbolt.
If there's an easy way for C++11 and C++14 this would be great but if there's only one for C++17 and above this would also help a lot.
The issue is std::max not your function.
There is no way you could modify your function to make it accept a set of overloads. A set of overloads is just not something you can pass along. What you can pass along is an object with overloaded operator(). For example
struct foo {
template <typename T> bool operator()(T a,T b){return a+b;}
};
f(foo{}); // OK
std::max however is a function template and you need to instantiate the function before the function can be passed to f. Nothing you can do about that. Though you not necessarily need std::function or static_cast to pick the right overload. As mentioned in a comment you can do
f([](int a, int b) { return std::max(a, b); });
This triggers instantiation of std::max<int> inside the lambda, or if you prefer to select the type inside f you can do similar as in the above example:
f([](auto a, auto b) { return std::max(a,b); });
This lambda expression is similar to the above foo. You have a concrete object and only the operator() is a template which only gets instantiated when called, such that in f you could even do:
template <typename F>
int f(F g)
{
if (some_condition) return g(1,2); // calls std::max<int>
else return g(1.2,1.4); // calls std::max<double>
// (though int is returned anyhow)
}
f([](auto a, auto b) { return std::max(a,b); });
Im trying to create a generic function Foo that will accept an argument and Op what will be applied to it.
template <template<class> class Op>
float foo(float boo) {
return Op(boo);
}
template <template<class> class Op>
float foo(float a, float b) {
return Op(a, b);
}
void caller() {
float boo = 2.3;
auto res1 = foo<std::plus>(boo, boo); // works
auto res2 = foo<std::sqrt>(boo); // fail. error: no instance of overloaded function.
auto res3 = foo<std::exp>(boo); // fail. error: no instance of overloaded function
}
I think its related that std::sqrt is
"A set of overloads or a function template accepting an argument of
any integral type. "
while std::plus is
Function object for performing addition.
Can someone, please, help fix this? How do i pass std::sqrt and std::exp to foo?
As you've identified, the problem is that your template expects a type (because that's how you've written it), and though std::plus is a type (a functor), std::sqrt is a function.
It's hard to give a concrete solution for your problem, because you never showed your usage of Op.
But, generally, this is easy to do with an auto template parameter:
template <auto Op>
float foo(const float boo) {
return Op(boo);
}
If your version of C++ is too old, you'll need to add a version that takes a function pointer instead.
std::sqrt is an overloaded function, not a type. A simple fix would be to write a generic lambda that wraps std::sqrt, and then use its type when calling foo, like this:
auto sqrt = [](auto n) { return std::sqrt(n); };
auto res2 = foo<decltype(sqrt)>(boo); // ok
And you can do the same for std::exp.
Whether this is a good fix depends on how you want to use the Op parameter, which is not clear from the question.
You can't pass an overload set as a template argument. A simple workaround could be to wrap sqrt and exp into functors with a templated operator():
struct Sqrt {
template<class T>
T operator()(T t) const { return std::sqrt(t); }
};
struct Exp {
template<class T>
T operator()(T t) const { return std::exp(t); }
};
Then the following will work
auto res2 = foo<Sqrt>(boo);
auto res3 = foo<Exp>(boo);
I have two variables and an operator (could be any of +, - , /, comparison...).
Is it a good idea to write a function that takes 2 arguments and the operator as the parameters?
Function may be something like below
T foo(int a,int b, sometype(not sure) operator)
and then make a string out of that
foo(a,b,+);
as a+b
Would this be a good approach or is there any other approach?
You can't. Operators are special, they are not ordinary functions. (For instance, operators can have short circuit evaluation and have no overload resolution if all operands are built-in types. Functions cannot do that.)
Pass a binary operation object instead, like:
template <class BinaryOp>
int fun(int, int, BinaryOP);
You can then pass functors like an instance of std::plus<> or binary lambdas† as a third argument. This is a common practice in C++.
Note that functors wrapping the built in operators, such as the aforementioned std::plus, are readily available in the header <functional>.
Sample code for reference:
#include <iostream>
#include <functional>
template <class T>
void fun (int i, int j, T t) {
std::cout << t(i,j) << "\n";
}
int main () {
fun(1,2,std::plus<>{}); // Or std::plus<int>{} in C++11
fun(1,2,[](auto i, auto j){return i * j;}); // Again, with explicit types for C++11
}
This will print
3
2
†As this is tagged C++11: The functors std::plus<T=void> etc. as used in this answer are available in C++14 and later. In C++11, you need to provide a template argument like std::plus<int>. Same goes for the lambda, which would need to become [](int i, int j){...}.
Operators cannot be passed that way, it wouldn't compile: the languages doesn't allow that. You could pass a character that describes the operation to do:
template <class T>
T foo(T lhs, T rhs, char op)
{
switch (op)
{
case '+':
return lhs + rhs;
// other operators
}
}
Another option is passing a function that does the actual computation as parameter:
template <class T, class Operator>
T foo(T lhs, T rhs, Operator op)
{
return op(lhs, rhs);
}
Now you can write your Operators or use the ones already provided: std::plus, std::minus etc. You find them in <functional>.
// ...
foo(5, 10, std::plus<int>{})
If you want to have your versions of these, write the required callables as lambdas or functions:
template <class T>
T add(T lhs, T rhs) { return lhs + rhs; }
foo(5, 10, add<int>);
foo(5, 10, [](int a, int b){ return a + b; }); // or use `auto` to make it generic
I was thinking about the implicit templates of C++14, and I'm trying to declare a function to match an specific argument type (SFINAE and traits still give me headaches). I'm not sure how to explain what I want, but I'm trying to make a Y combinator (just to see if it's possible, not intended for production).
I'm trying to declare a function:
template<typename T>
my_traits<T>::return_type Y(T t) {
// ...
};
Such that T is a function (or a functor) that matches
std::function<R(F, Args...)>
// where F (and above return_type) will be
std::function<R(Args...)>
Which would take any number of arguments, but the first should be a function with the same return type and the same arguments (except this function itself). The first parameter to the operator () of the functor is a template.
The usage I want to achieve:
auto fib = [](auto myself, int x) {
if(x < 2)
return 1;
return myself(x - 1) + myself(x - 2);
};
// The returned type of fib should be assignable to std::function<int(int)>
I wasn't able to take the return type of the T type (because of the overloaded operator ()). What I'm trying to make is possible? How could I make it?
Edit:
Seeing it from a different angle, I'm trying to make this work:
struct my_functor {
template<typename T>
char operator () (T t, int x, float y) { /* ... */ };
};
template<typename T>
struct my_traits {
typedef /* ... */ result_type;
/* ... */
};
// I want this to be std::function<char(int, float)>, based on my_functor
using my_result =
my_traits<my_functor>::result_type;
It is not possible in C++14 return type deduction to deduce int(int) out of int(T, int) as OP desires.
However, we can mask the first parameter of the result using the following approach. The struct YCombinator is instantiated with a non-recursive function object member, whose first argument is a version of itself without the first argument. YCombinator provides a call operator that receives the arguments of the non-recursive function and then returns its function object member after substituting itself for the first argument. This technique allows the programmer to avoid the messiness of myself(myself, ...) calls within the definition of the recursive function.
template<typename Functor>
struct YCombinator
{
Functor functor;
template<typename... Args>
decltype(auto) operator()(Args&&... args)
{
return functor(*this, std::forward<Args>(args)...);
}
};
A make_YCombinator utility template allows for a streamlined usage pattern. This compiles run runs in GCC 4.9.0.
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }
int main()
{
auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });
for (int i = 0; i < 10 ; ++i)
cout << "fib(" << i << ") = " << fib(i) << endl;
return 0;
}
Since the non-recursive function is not defined at time that the recursive function is defined, in general the recursive function must have an explicit return type.
Edit:
However, it may be possible for the compiler to deduce the return type in certain cases if the programmer takes care to indicate the return type of the recursive function before use of the non-recursive function. While the above construction requires an explicit return type, in the following GCC 4.9.0 has no problem deducing the return type:
auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
To pin this down just a bit further, here is a quote from the draft C++14 standard on return type deduction [7.1.6.4.11]:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
Once a return statement has been seen in a function, however, the
return type deduced from that statement can be used in the rest of the
function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
It's a really hacky approach, and has severe limitations, but here it goes:
First, we need a class that pretends to support every possible operation (as far as possible), such as the fake_anything class. Note that this isn't perfect since at a minimum . and :: won't work. To fake a functor, we give it a function call operator:
template<class... Ts> fake_anything operator()(Ts&&...) const;
Knowing that the lambda has only one operator(), and that operator() has only one template parameter allows us to extract its signature with decltype(&T::operator()<fake_anything>).
For this to work, the lambda's return type must be explicitly specified; it can't use deduction, since otherwise the deduced return types will probably conflict.
Finally we can obtain the other arguments to the lambda and the return type using the standard partial specialization approach:
template<class T>
struct extract_signature;
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...)> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...) const> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
// other cv- and ref-qualifier versions omitted - not relevant to lambdas
// we can also static_assert that none of Args is fake_anything, or reference to it, etc.
And add an alias template to hide all the ugliness of the hack:
template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
And finally we can check that
static_assert(std::is_same<signature_t<decltype(fib)>,
std::function<int(int)>>::value, "Oops");
Demo.
The limitations:
The return type of operator() must be explicitly specified. You cannot use automatic return type deduction, unless all of the return statements return the same type regardless of the return type of the functor.
The faking is very imperfect.
This works for operator() of a particular form only: template<class T> R operator()(T, argument-types...) with or without const, where the first parameter is T or a reference to possibly cv-qualified T.
I'm playing around with lambda functions in gcc 4.6.2, and would like to implement a templated "map" function like this:
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, const std::function<B(A)> f) {
std::vector<B> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
This doesn't work, because the test code:
int main(int argc, char **argv) {
std::vector<int> list;
list.push_back(10);
list.push_back(20);
list.push_back(50);
std::vector<int> transformed = map(list, [](int x) -> int { return x + 1; });
std::for_each(begin(transformed), end(transformed), [](int x) { printf("-> %d\n", x); });
return 0;
}
gives this error:
test.cpp:49:80: error: no matching function for call to ‘map(std::vector<int>&, main(int, char**)::<lambda(int)>)’
test.cpp:49:80: note: candidate is:
test.cpp:6:49: note: template<class A, class B> std::vector<B> map(const std::vector<A>&, std::function<B(A)>)
If I remove the templating, and use a vector directly, it compiles fine:
std::vector<int> map(const std::vector<int>& orig, const std::function<int(int)> f) {
std::vector<int> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
so it must be a problem with the way I'm defining the template.
Has anyone run into this before? I know lambdas are incredibly new.
You don't need to use std::function. Just make the predicate parameter a template value. For example,
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {
std::function<> is more useful as a member value type or for defining non-templated code.
The problem is that the compiler can't figure out what to use for B. In order to determine that type it wants to use the function<> you pass in for f, but you don't pass an std::function<> directly. You pass in something you expect to be used to construct a function<>. And in order to do that implicit construction it needs to know the type of argument. So you've got this circular dependency where the type of argument depends on what you pass in, but what gets passed in depends on the type of argument.
You can break this circular dependency by specifying the template parameters, such as map_<int,int>(list, [](int x) -> char { return x + 1; });
(although I see the functor actually returns a char, not an int, so if the type deduction worked for you here you'd be getting back a vector<char> which cannot be converted to a vector<int> when you assign the result to transformed)
However as has been pointed out, generally templates take functors as just a plain template type:
template<typename A,typename Func>
auto map_(const std::vector<A>& orig, Func f) -> std::vector<decltype(f(A()))> {
std::vector<decltype(f(A()))> rv;
/*...*/
}
(we use the trailing return type because we need to use the expression f in the return type, which isn't available unless the return type comes afterwards.)
This allows the template to deduce the functor type directly and avoids any type conversions and best allows for optimization.
It's also customary to use iterators as arguments on these sorts of functions, in which case your function is just a wrapper around std::transform, so you can just use that directly. I'm not sure there's a whole lot of value in a special version that deals with vectors specifically.
I'm tackling with lambdas too and i noticed that you can declare a function pointer in a function definition's parameter list and when you make a call to that function you can pass a lambda expression as an argument if it matches the function prototype of course.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T,typename C>
struct map {
typedef C (*F)(const T&);
std::vector<C> rv;
map () {}
map (const std::vector<T>& o,F f) {
rv.resize(o.size());
std::transform (o.begin(),o.end(),rv.begin(),f);
}
~map () {}
operator std::vector<C> () const {
return rv;
}
};
int main () {
std::vector<int> asd(5,12);
std::vector<char> transformed=map<int,char>(asd,[](const int& x)->char {return x+1;});
std::copy (transformed.begin(),transformed.end(),std::ostream_iterator<int>(std::cout," "));
}