开发者

How to write a boost::lambda functor that returns a new functor

开发者 https://www.devze.com 2023-02-15 22:52 出处:网络
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.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消