Perform argument substitution on nested boost::bind without composition

若如初见. 提交于 2019-12-30 05:16:30

问题


Suppose I have a function which takes a nullary functor as an argument:

void enqueue( boost::function<void()> & functor );

I have another function which takes an int and does something internally:

void foo( int a);

I would like to nest, but not compose, these together so that I get a functor with the signature:

boost::function<void(int)> functor

Which when called with a value - say 4 - performs the following:

enqueue( boost::bind(&foo, 4) )

My first attempt was the following:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::bind(&foo,_1))

This fails because bind performs composition when given a nested bind. foo was first called, then the value void was "returned" to enqueue, which fails.

My second attempt was the following:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::protect( boost::bind(&foo, _1) ) )

This failed because enqueue accepts a nullary, not unary functor.

Can what I'm seeking be done?

Other information:

  • This is basically identical to the unanswered boost forum question from 6 years ago: http://lists.boost.org/boost-users/2004/07/7125.php
  • Some reading suggests that using boost::lambda::bind with boost::lambda::unlambda and boost::lambda::protect may do what I'm seeking. Unfortunately boost::lambda has an unacceptably low number of allowed placeholders (3), and high compile-time overhead.

回答1:


Interesting question...

What you basically want is a "bound call to bind". In the same manner than binding a call to foo(x, y) is written bind(&foo, x, y), binding a call to bind(&foo, x) should be like bind(&bind, &foo, x). However, taking the address of an overloaded function quickly gets ugly and, as boost::bind has more overloads than I could count, it gets pretty ugly:

// One single line, broken for "readability"
boost::function<void(int)> f = boost::bind(
  &enqueue, 
  boost::bind(
    static_cast<
      boost::_bi::bind_t<
        void, void(*)(int), boost::_bi::list_av_1<int>::type
      >
      (*)(void(*)(int), int)
    >(&boost::bind), 
    &foo, 
    _1
  )
);

You'll probably agree that, while "interesting", the above won't win readability contests. Separating the obtention of the proper bind overload from the rest makes things a bit more manageable:

boost::_bi::bind_t<void, void(*)(int), boost::_bi::list_av_1<int>::type>
  (*bind_foo)(void(*)(int), int) = &boost::bind;

boost::function<void(int)> q = boost::bind(&enqueue, boost::bind(bind_foo, &foo, _1));

but I still hesitate to recommend it ;)

Edit:

Answering the OP's comment about how/if C++0x would help to clean the syntax: It does:

auto f = [](int i){enqueue([=](){foo(i);});};



回答2:


'Nest' manually:

class Enqueuer {
 std::function<void (int)> mFunc;

public:
 void operator()(int pVal) {
  enqueue(std::bind(mFunc, pVal));
 }

 Enqueuer(std::function<void (int)> pFunc)
  : mFunc(pFunc) {}
};

// usage:
Enqueuer e(foo);
e(1);
e(2);
e(3);


来源:https://stackoverflow.com/questions/4091576/perform-argument-substitution-on-nested-boostbind-without-composition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!