问题
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