How to write a boost::lambda functor that returns a new functor
How can I write a lambda expression with two placeholders, one for the callable object, and one for the function argument, such that supplying the callable object first returns a unary function.
In the example below, generate
should be a lambda expression with the first placeholder for the callable object itself, and the second placeholder for the argument. Calling generate(c)
should return a unary function that is only missing the function call argument. In fact, it somehow returns type bool
already, as proved by the static assert.
#include <boost/lambda/bind.hpp>
struct Arg {
};
struct Callable : std::unary_function<Arg, bool> {
bool operator()( Arg const& a ) const { return true; }
};
int main( int argc, const char* argv[] ) {
BOOST_AUTO(generate, boost::lambda::bind(boost::lambda::_1, boost::lambda::protect(boost::lambda::_1)));
Callable c;
BOOST_AUTO(fn, generate(c));
BOOST_STATIC_ASSERT((boost::is_same<BOOST_TYPEOF(fn), bool>::val开发者_JS百科ue));
Arg a;
bool b = fn(a);
_ASSERT(b==true);
}
If using Boost.Phoenix the answer would have been a little easier:
#include <boost/phoenix/phoenix.hpp>
struct callable
{
typedef bool result_type;
bool operator()(int) const
{
return true;
}
};
int main()
{
using phx::bind;
using phx::lambda;
using phx::arg_names::_1;
using phx::local_names::_a;
auto generate = lambda(_a = _1)[bind(_a, _1)];
auto fn = generate(callable());
bool b = fn(8);
}
Not that this solution is far more generic than the version posted by the OT. It can be used with any unary function object, no matter what argument, no matter what return type.
The downside, you need to use the current boost trunk ...
I have solved my own problem, albeit not as elegantly as I had hoped:
struct FCreateBind {
typedef boost::_bi::bind_t<bool, Callable, boost::_bi::list2<boost::arg<1>, boost::arg<2> > > result_type;
result_type operator()( Callable const& c ) const {
return boost::bind<bool>(c, _1);
}
};
BOOST_AUTO(generate, boost::bind(FCreateBind(), _1));
BOOST_AUTO(fn, generate(Callable());
bool b = fn(Arg());
Of course, in this simple example I could just write BOOST_AUTO(generate, boost::lambda_1)
since Callable
itself is the callable object. But I was looking for a way to set the arguments of Callable
beforehand so the generated function fn
is a nullary function. This solution would let me do this inside FCreateBind
.
FCreateBind
can probably be eliminated as well, but I have not yet figured out how to define the pointer to the overloaded global function boost::bind
.
Though I'm not 100% sure I understand the question, the following code might meet your purpose:
template< class R >
struct FCreateBind {
typedef boost::function< R() > result_type;
template< class T, class U >
result_type operator()( T const& x, U const& y ) const {
return boost::bind( x, y );
}
};
int main() {
BOOST_AUTO( generate, boost::bind( FCreateBind< bool >(), Callable(), _1 ) );
BOOST_AUTO( fn, generate( Arg() ) );
bool b = fn();
}
That being said, probably this isn't as pretty as the questioner
expects...
As you mentioned, if we specify one of the overloads of boost::bind
explicitly, FCreateBind
wouldn't be needed.
However, as far as I saw, there seems not to be the portable way to specify
the overload.
So, in this case, probably we have to depend on the internal of boost
.
For your information, the following code could be compiled when I tested:
int main() {
namespace bb = boost::_bi; // Sorry, for brevity
bb::bind_t< bb::unspecified, Callable, bb::list1< bb::value< Arg > > >
(*bi)( Callable, Arg ) = boost::bind< bb::unspecified, Callable, Arg >;
BOOST_AUTO( generate, boost::bind( bi, Callable(), _1 ) );
BOOST_AUTO( fn, generate( Arg() ) );
bool b = fn();
}
Hope this helps
精彩评论