Передать и вызвать функцию-член (boost :: bind / boost :: function?) - PullRequest
6 голосов
/ 09 марта 2011

У меня, наверное, очень простая проблема: передать и вызвать функцию-член в классе. Я знаю, что хочу использовать BOOST bind (и / или функцию), но я до сих пор не понял концепцию.

Следующий код компилируется и выполняется с проблемой. Но когда я хочу изменить функцию «f3» на нестатическую функцию класса, тогда начинается самое интересное:

#include <iostream>
#include <inttypes.h> 
#include <boost/bind.hpp>
#include <boost/function.hpp>

class Test
{
public:
  void f1();
private:
  void f2(void (*callfunc)(uint32_t));
  static void f3(uint32_t x);
};

void Test::f1(){
  f2(f3);
}

void Test::f2(void (*callfunc)(uint32_t)){
  (*callfunc)(42);
}

void Test::f3(uint32_t x){
  std::cout << "x: " << x << std::endl;
}

int main(int argc, char ** argv)
{
  Test ct;
  ct.f1();
  return 0;
}

Теперь, после изменения

static void f3(uint32_t x);

до

* * 1010

компилятор недоволен и сообщает мне: «ошибка: не найдена соответствующая функция для вызова метода Test :: f2 ()» *

Прочитав несколько сообщений SO, касающихся boost :: bind и boost :: function, я думаю, что мне нужно изменить определение функции f2 () и того, как f1 () вызывает функцию f2 (), давая f3 () в качестве цели вызывать, но кроме этого ... о каждой комбинации функций boost :: bind и boost, которую я пробовал, с треском не компилируется.

Как мне написать это? В качестве дополнительного вопроса: есть ли простые вводные чтения на boost :: bind и boost :: function? Документы BOOST на самом деле мне там не помогли.

B.

Ответы [ 2 ]

8 голосов
/ 09 марта 2011

boost :: function - это шаблонный класс, который принимает сигнатуру функции.Вы также можете использовать function0, function1 и т. Д.

boost::function< void(uint32_t) >

определяет «вызываемый», который выглядит как функция, то есть он принимает один параметр типа uint32_t и возвращает void,

Соответствующий нумерованный шаблон - function1< void, uint32_t >.Они всегда сначала указывают тип возвращаемого значения, а затем параметры в следующем порядке.

boost::bind - это особая функция, которая выводит аргументы, которые вы передаете ей, и создает для вас функтор.

Этоне создаст для вас пустоту (uint32_t), он создаст что-то с шаблоном единицы.

Поэтому измените свою подпись на:

void f2(boost::function<void(uint32_t)>);

Тогда вы можете назвать это так:

f2( boost::bind( &Test::f3, this, _1 ) );

Обратите внимание, что странный _1 является "заполнителем", сообщающим boost :: bind, где он должен ввести параметр, в данном случае uint32_t

5 голосов
/ 09 марта 2011

Сначала я объясню причину, по которой удаление static приводит к ошибке компиляции:

Посмотрите на эту подпись:

void (*callfunc)(uint32_t)

Это указатель на свободную функцию, которая принимает uint32_t и возвращает void. Когда f3 объявлено внутри Test как

void f3(uint32_t x);

затем f3 является функцией-членом класса Test, которая принимает uint32_t и возвращает void. Следовательно, f3 не соответствует типу аргумента, ожидаемого f2.

Что касается того, как boost::function и boost::bind могут использоваться для предоставления решения:

void Test::f1(){
    boost::function<void (uint32_t)> f = boost::bind(&Test::f3, this, _1);
    f2(f);
}

Обновление:

Наконец, относительно учебника: я нашел это полезным при изучении функторов (что и есть boost::function и boost::bind возвращаются) в прошлом. В нем конкретно не упоминается boost, но как только вы поймете, что именно происходит на более низком уровне, вы обнаружите, используя boost бриз.

...