Выполнить подстановку аргумента для вложенного boost :: bind без композиции - PullRequest
4 голосов
/ 03 ноября 2010

Предположим, у меня есть функция, которая принимает нулевой функтор в качестве аргумента:

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

У меня есть другая функция, которая принимает int и выполняет что-то внутренне:

void foo( int a);

Я былюблю вкладывать, но не составлять их вместе, так что я получаю функтор с подписью:

boost::function<void(int)> functor

, который при вызове со значением, скажем, 4, выполняет следующее:

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

Моя первая попытка была следующей:

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

Это не удалось, потому что связывание выполняет компоновку, если дано вложенное связывание.Сначала был вызван foo, затем значение void было «возвращено» для постановки в очередь, что не удалось.

Моя вторая попытка была следующей:

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

Это не удалось, поскольку enqueue принимает нулевое значение, а неунарный функтор.

Может ли то, что я ищу, быть сделано?

Другая информация:

  • Это в основном идентично оставшемуся без ответа вопросу на форуме поддержки от 6 лет назад: http://lists.boost.org/boost-users/2004/07/7125.php
  • Некоторые читатели предполагают, что использование boost :: lambda :: bind с boost :: lambda :: unlambda и boost :: lambda :: protect может сделать то, что я ищу.К сожалению, boost :: lambda имеет недопустимо низкое количество разрешенных заполнителей (3) и высокие накладные расходы во время компиляции.

Ответы [ 2 ]

4 голосов
/ 04 ноября 2010

Интересный вопрос ...

То, что вы в основном хотите, это «связанный вызов связать». Таким же образом, как привязка вызова к foo(x, y) записывается bind(&foo, x, y), привязка вызова к bind(&foo, x) должна быть такой же, как bind(&bind, &foo, x). Однако, получение адреса перегруженной функции быстро становится уродливым, и, поскольку boost::bind имеет больше перегрузок, чем я мог рассчитывать, это становится довольно уродливым:

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

Вы, вероятно, согласитесь с тем, что, несмотря на "интересность", вышеприведенное не будет выигрывать конкурсы по читабельности. Отделение получения правильной перегрузки связывания от остальных делает вещи более управляемыми:

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

но я все еще не решаюсь рекомендовать его;)

Edit:

Ответ на комментарий ОП о том, как / если C ++ 0x поможет очистить синтаксис: Это делает:

auto f = [](int i){enqueue([=](){foo(i);});};
0 голосов
/ 04 ноября 2010

«Гнездо» вручную:

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