Как написать буст:: лямбда-функтор, который возвращает новый функтор
Как я могу написать лямбда-выражение с двумя заполнителями, один для вызываемого объекта и один для аргумента функции, так что предоставление вызываемого объекта сначала возвращает унарную функцию.
В приведенном ниже примере generate
должно быть лямбда-выражением с первым заполнителем для самого вызываемого объекта и вторым заполнителем для аргумента. призвание 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);
}
3 ответа
Если использовать 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. Он может использоваться с любым унарным объектом функции, независимо от того, какой аргумент, независимо от того, какой тип возвращаемого значения.
Недостатком является то, что вам нужно использовать текущую форсированную магистраль...
Я решил свою собственную проблему, хотя и не так элегантно, как я надеялся:
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
,
Хотя я не уверен на 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::bind
в явном виде, FCreateBind
не понадобится Однако, насколько я видел, похоже, что не существует портативного способа определения перегрузки. Таким образом, в этом случае, вероятно, мы должны зависеть от внутреннего 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();
}
Надеюсь это поможет