4

如何编写带有两个占位符的 lambda 表达式,一个用于可调用对象,一个用于函数参数,以便首先提供可调用对象返回一元函数。

在下面的示例中,generate应该是一个 lambda 表达式,其中第一个占位符代表可调用对象本身,第二个占位符代表参数。调用generate(c)应该返回一个只缺少函数调用参数的一元函数。事实上,bool正如静态断言所证明的那样,它已经以某种方式返回了类型。

#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>::value));
    Arg a;
    bool b = fn(a);
    _ASSERT(b==true);
}
4

3 回答 3

4

如果使用 Boost.Phoenix,答案会简单一些:

#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);
}

并不是说这个解决方案比 OT 发布的版本更通用。它可以与任何一元函数对象一起使用,无论是什么参数,无论返回类型是什么。

不利的一面是,您需要使用当前的升压后备箱...

于 2011-03-10T20:35:08.193 回答
1

我已经解决了自己的问题,尽管没有我希望的那么优雅:

   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());

当然,在这个简单的例子中,我可以直接写BOOST_AUTO(generate, boost::lambda_1),因为Callable它本身就是可调用对象。但我一直在寻找一种方法来Callable预先设置参数,所以生成的函数fn是一个空函数。这个解决方案可以让我在里面做这个FCreateBind

FCreateBind可能也可以消除,但我还没有弄清楚如何定义指向重载全局函数的指针boost::bind

于 2011-03-10T10:08:19.660 回答
0

虽然我不是 100% 确定我理解了这个问题,但以下代码可能符合您的目的:

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();
}

话虽如此,这可能并不像提问者所期望的那样漂亮......
正如您所提到的,如果我们明确指定重载之一boost::bindFCreateBind则不需要。但是,据我所见,似乎没有指定重载的可移植方式。所以,在这种情况下,可能我们不得不依赖boost.
供您参考,我测试时可以编译以下代码:

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();
}

希望这可以帮助

于 2011-03-10T22:59:32.593 回答