With C++11, we get lambdas, and the possibility to create functions/functors/closures on-the-fly where we actually need them, not somewhere where they don't really belong.
In C++98/03, a nice way to make function-local functors/closures would've been the following:
struct{
void operator()(int& item){ ++item; }
}foo_functor;
some_templated_func(some_args, foo_functor);
Sadly, you can't use local types for templates (Visual Studio allows this with language extensions enabled). My train of though then went the following way:
struct X{
static void functor(int& item){ ++item; }
};
some_templated_func(some_args, &X::functor);
The obvious problem being, that you can't save any state, since local structs/classes can't have static members.
My next thought to solving that problem was using a mix of std::bind1st
and std::mem_fun
and non-static methods & variables, but unfortunately std::mem_fun
somehow chokes with std::mem_fn(&X::functor)
, which again might be because local struct/classes can't be used in templates:
// wanted, not working solution
struct X{
int n_;
X(int n) : n_(n) {}
void functor(int& item) const { item += n_; }
};
X x(5);
some_templated_func(some_args,std::bind1st(std::mem_fun(&X::functor),&x));
Fails under VC9 & VC10 (with /Za
, disabled language extensions) with the following error
error C2893: Failed to specialize function template 'std::const_mem_fun1_t<_Result,_Ty,_Arg> std::mem_fun(_Result (_Ty::* )(_Arg) const)'
With the following template arguments:
'void'
'main::X'
'int &'
Or under gcc 4.3.4 with this error
error: no matching function for call to ‘mem_fun(void (main()::X::*)(int&))’
Funnily enough, VC9 / VC10 still chokes on the above example, even with language extensions enables:
error C2535: 'void std::binder1st<_Fn2>::operator ()(int &) const' : member function already defined or declared
So, is the functionality stated in the title somehow, anyhow achievable? Or am I making a mistake in the last example in how I use std::bind1st
or std::mem_fun
?
bind1st
only works for binary functions, and in general it's very restricted. mem_fn
works with non-static member functions only; for your application you would want ptr_fun
.
Really the best tool for the job in C++03 is Boost Bind, or I'll demonstrate here with tr1::bind
which is (in my opinion) more portable.
#include <tr1/functional>
#include <iostream>
#include <algorithm>
using namespace std::tr1::placeholders;
int nums[] = { 1, 2, 4, 5, 6, 8 };
int main() {
struct is_multiple {
static bool fn( int mod, int num ) { return num % mod == 0; }
};
int *n = std::find_if( nums, nums + sizeof nums/sizeof*nums,
std::tr1::bind( is_multiple::fn, 3, _1 ) );
std::cout << n - nums << '\n';
}
Yes you can, but you'll have to implement one or more virtual methods declared in an interface.
template<typename Arg, typename Result>
struct my_unary_function
{
virtual Result operator()(Arg) = 0;
};
template<typename Arg, typename Result>
struct my_unary_functor
{
my_unary_function<Arg, Result> m_closure;
my_unary_functor(my_unary_function<Arg, Result> closure) : m_closure(closure) {}
Result operator()(Arg a) { return m_closure(a); }
};
template<typename T, TFunctor>
void some_templated_function( std::vector<T> items, TFunctor actor );
Then you can define and use a local closure:
void f()
{
std::vector<int> collection;
struct closure : my_unary_function<int, int>
{
int m_x, m_y;
closure(int x, int y) : m_x(x), m_y(y) {}
virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
};
some_templated_function( collection, my_unary_functor<int,int>(closure(1, 5)) );
}
Credit to @Omnifarious for this improvement (my_unary_functor
not needed):
void f()
{
std::vector<int> collection;
struct closure : my_unary_function<int, int>
{
int m_x, m_y;
closure(int x, int y) : m_x(x), m_y(y) {}
virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
};
// need a const reference here, to bind to a temporary
const my_unary_functor<int,int>& closure_1_5 = my_unary_functor<int,int>(closure(1, 5))
some_templated_function( collection, closure_1_5 );
}
If this was doable in C++03, why would C++0x have introduced lambdas? There's a reason lambdas exist, and it's because binding and all the other C++03 solutions suck hideously.