Reputation: 4484
I would like to get some function/functor acts as a composite function/functor:
Specifically, I have functions f(x, y)
, and g(u, v)
, and I want to create a function pointer or functor h(t) = f(g(t,C1), C2)
, so that I can pass functor h
into a for_each() loop, where C1, C2 are some constants.
Or, let's do it in my real example:
I have a function double g(T1 u, T2 v)
which calculate something. I want to loop through all u
from a vector vector<T1> vecInput
, with fixed 2nd argument t2VConst
. After calculating all these numbers, I want to save them into a vector vector<double> results
.
I would like to do it with something similar to this:
foreach(vecInput.begin(), vecInput.end(), std::bind2nd(&results::push_back, std::bind2nd(g, t2VConst)))
Note that in this case, the f(x,y)
function is really a member function vector::push_back
. (It seems that push_back
only have one argument. However, as a member function, it has an extra argument, which is the object itself.)
To make the case worse, I really have to do it in C++03, not C++11. Is there any solution? Moreover, I wish the solution can be cleaner (if it can be done in one line like above).
UPDATE
Related issue for bind2nd()
:
I got compile error, and now I reduce it to a simpler code to look at it:
#include <functional>
#include <algorithm>
#define CASE2 // choose define of CASE1 to CASE3
#ifdef CASE1
double g(double x, double y) // 1. OK
#endif
#ifdef CASE2
double g(double &x, double y) // 2. overload error
#endif
#ifdef CASE3
double g(double *x, double y) // 3. OK
#endif
{
#ifdef CASE2
x = 5.0;
#endif
#ifdef CASE3
*x = 5.0;
#endif
// Note: no case1, since in case 1, x is a local variable,
// no meaning to assign value to it.
return 3.0;
}
int main(int argc, char *argv[])
{
double t = 2.0;
double u;
#if defined(CASE1) || defined(CASE2)
u = std::bind2nd(std::ptr_fun(&g), 3.0)(t);
#endif
#ifdef CASE3
u = std::bind2nd(std::ptr_fun(&g), 3.0)(&t);
#endif
}
I don't know why CASE 2 fails...
Upvotes: 1
Views: 557
Reputation: 48447
I have functions
f(x, y)
, andg(u, v)
, and I want to create a function pointer or functorh(t) = f(g(t,C1), C2)
. I have to do it in C++03.
It's not possible to compose functions using only the adapters available in the standard library of C++03. Obviously, nothing stops you from implementing this functionality on your own. However, if you want to utilize any of the existing libraries, and get a true one-liner, there are few alternatives:
libstdc++ is shipped with the standard library extensions from SGI. It provides several additional adapters and functors, namely: compose1
, compose2
and constant1
. They can be combined in the following way:
#include <functional>
#include <ext/functional>
int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;
__gnu_cxx::compose2(std::ptr_fun(&f)
, std::bind2nd(std::ptr_fun(&g), C1)
, __gnu_cxx::constant1<int>(C2)
)(arg);
The initial implementation of C++11's std::bind
can be also found in tr1
extension libraries:
#include <tr1/functional>
int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;
std::tr1::bind(&f
, std::tr1::bind(&g
, std::tr1::placeholders::_1
, C1)
, C2
)(arg);
Boost.Bind library is probably the most portable solution:
#include <boost/bind.hpp>
int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;
boost::bind(&f, boost::bind(&g, _1, C1), C2)(arg);
The
f(x,y)
function is really a member functionvector::push_back
When it comes to binding a member function in C++03 you would normally use std::mem_fun
together with std::bind1st
to bind the object parameter:
Class object;
std::bind1st(std::mem_fun(&Class::func), &object)(arg);
However, this will fail for member functions taking its parameter by reference. Once again, you could use Boost/TR1 instead:
boost::bind(&std::vector<double>::push_back
, &results
, boost::bind(&g, _1, C1)
)(arg);
Note that when switching to C++11 you'd need to manually resolve overloaded std::vector<double>::push_back
.
But fortunately, your use-case qualifies to be replaced by std::transform
algorithm with std::back_inserter
, that will take care of calling push_back
member function of your vector for transformed arguments.
#include <algorithm>
#include <functional>
#include <iterator>
int g(int u, int v);
const int C1 = 2;
std::vector<int> input, output;
std::transform(input.begin(), input.end()
, std::back_inserter(output)
, std::bind2nd(std::ptr_fun(&g), C1));
Upvotes: 1
Reputation: 179799
It's important to remember that these library functions aren't magic, they just deduce rather involved types.
In your case, you don't need all this flexibility, if only because you know you'll need vector::push_back
. Instead of deducing a rather involved type, just create a type explicitly to capture the function. There's even a library type which does this, std::back_insert_iterator
, but in general you can do it yourself.
So, you'll end up with a template class that takes typenames T1 and T2, stores &g
, T2 C2
, and std::vector<double>&
. It simply implements void operator()(T1 t1) { v.pus_back(g(t1, C2)); }
.
Upvotes: 0