boost::bind неявное преобразование в boost::function или указатель на функцию

Я использую boost:: function следующим образом:

template<class T1>
void run(boost::function<void (T1)> func, string arg)
{
    T1 p1 = parse<T1>(arg);
    func(p1);
}

При таком использовании все нормально:

void test1(int i)
{
    cout << "test1 i=" << i << endl;
}

...

boost::function<void (int)> f = &test1;
run(f, "42");

Я хочу иметь возможность напрямую передавать необработанный указатель функции, поэтому я перегружаю функцию run() следующим образом:

template<class T1>
void run(void (*func)(T1), string arg)
{
    T1 p1 = parse<T1>(arg);
    (*func)(p1);
}

...

run(&test1, "42"); // this is OK now

Теперь я хочу передать результат boost::bind функции run(). Так:

void test2(int i, string s)
{
    cout << "test2 i=" << i << " s=" << s << endl;
}

...

run(boost::bind(&test2, _1, "test"), "42"); // Edit: Added missing parameter 42

Но это не скомпилируется: Отредактировано

bind.cpp: In function ‘int main()’:
bind.cpp:33:59: error: no matching function for call to ‘run(boost::_bi::bind_t<void, void (*)(int, std::basic_string<char>), boost::_bi::list2<boost::arg<1>, boost::_bi::value<std::basic_string<char> > > >, std::string)’
bind.cpp:33:59: note: candidates are:
bind.cpp:7:6: note: template<class T1> void run(boost::function<void(T1)>, std::string)
bind.cpp:14:6: note: template<class T1> void run(void (*)(T1), std::string)

Как мне перегрузить run(), чтобы принять boost::bind()?

Изменить 2

Я знаю, что могу сделать это так:

boost::function<void (int)> f = boost::bind(&test2, _1, string("test"));
run(f, "42");

Но я бы хотел, чтобы использование было менее подробным.

Изменить 3

Изменен прототип run() с run(boost::function<void (T1)>, T1) на run(boost::function<void (T1)>, string) для уточнения фактического варианта использования. Ссылка Ответ Игоря Р.

Весь исходный файл можно получить здесь


person anorm    schedule 09.04.2013    source источник
comment
Неявного приведения не существует. Приведение — это то, что вы пишете в своем исходном коде, чтобы указать компилятору выполнить преобразование. Есть преобразования, которые компилятор может выполнять без приведения; такое преобразование является неявным преобразованием. Когда вы используете приведение, это явное преобразование.   -  person Pete Becker    schedule 09.04.2013
comment
Конечно. Название вопроса следует изменить.   -  person anorm    schedule 09.04.2013


Ответы (1)


Ни function, ни тип результата bind не могут быть преобразованы в указатель на функцию, поэтому вы не можете передать их функции run с ее текущей сигнатурой.

Однако вы можете изменить подпись run, чтобы она могла принимать любые вызываемые:

template<class F, class A1>
void run(F f, A1 arg)
{
  f(arg);
}

Теперь вы можете передать функцию указателя, связыватель, boost::function или что угодно вызываемое по вашему желанию, если оно ожидает 1 аргумент. (Обратите внимание, однако, что с этой тривиальной подписью run не будет беспрепятственно пересылать аргументы в f.)

person Igor R.    schedule 09.04.2013
comment
Да, решает проблему, которую я описал (+1). Однако фактическая функция run() должна знать тип аргумента, а аргумент не является частью реальной функции. - person anorm; 09.04.2013
comment
Реальная функция использует тип аргумента для вызова шаблонного синтаксического анализатора строк, чтобы я мог вызвать функцию, задав ей строковые аргументы, а функция run() анализирует аргументы как правильные типы и вызывает функцию. - person anorm; 09.04.2013
comment
@Доктор. Sbaitso То есть run должен принимать вызываемый объект, который ожидает 1 аргумент типа T, и этот тип должен быть автоматически выведен из сигнатуры фактического вызываемого объекта, переданного в run? Ну, на данный момент я не могу понять, как это сделать. Без автодедукции это было бы довольно тривиально: `шаблон ‹ класс A1, класс F › void run(F f, string a) { T1 p1 = parse ‹ T1 › (a); ф(р1); } ` Вызовите так: run < int > (test2, yourString); - person Igor R.; 09.04.2013