Проблема в том, что std::bind
обрабатывает «выражение привязки» (например, ваше applyWithFoo0
) иначе, чем другие типы. Вместо вызова foo1 с applyWithFoo0
в качестве параметра он пытается вызвать applyWithFoo0
и передать возвращаемое значение в foo1. Но applyWithFoo0
не возвращает ничего, что можно преобразовать в std::function<void(int)>
. Цель такой обработки "выражений привязки" состоит в том, чтобы сделать их легко компонуемыми. В большинстве случаев вы, вероятно, не хотите, чтобы выражение привязки передавалось как параметры функции, а только их результаты. Если вы явно заключаете выражение связывания в объект function<>
, объект function<>
будет просто передан в foo1 напрямую, так как он не является "выражением связывания" и, следовательно, не обрабатывается специально std::bind
.
Рассмотрим следующий пример:
#include <iostream>
#include <functional>
int twice(int x) { return x*2; }
int main()
{
using namespace std;
using namespace std::placeholders;
auto mul_by_2 = bind(twice,_1);
auto mul_by_4 = bind(twice,mul_by_2); // #2
auto mul_by_8 = bind(twice,mul_by_4); // #3
cout << mul_by_8(1) << endl;
}
На самом деле это компилируется и работает, потому что вместо того, чтобы дважды передавать функтор, как можно было бы ожидать от выражений связывания № 2 и № 3, bind фактически оценивает переданные выражения связывания и использует результат в качестве параметра функции дважды. . Здесь намеренно. Но в вашем случае вы случайно споткнулись об это поведение, потому что вы действительно хотите, чтобы привязка передала функции сам функтор вместо его оцененного значения. Обертывание функтора в объект function‹>, очевидно, является обходным путем.
На мой взгляд, это дизайнерское решение немного неудобно, потому что оно вносит неточность, о которой люди должны знать, чтобы иметь возможность правильно использовать привязку. Может быть, в будущем мы получим еще одну более приятную работу, например
auto applyFoo1 = bind( foo1, _1, noeval(applyWithFoo0) );
где noeval
указывает привязке не оценивать выражение, а передавать его прямо в функцию. Но, возможно, наоборот — явное указание bind передать результат функтора в функцию — было бы лучше:
auto mul_by_8 = bind( twice, eval(mul_by_4) );
Но я думаю, теперь уже слишком поздно для этого...
person
sellibitze
schedule
25.07.2012
std::function
, по-видимому, обеспечивает волшебное преобразование, которое делает то, что хочет OP. В противном случае правая часть не имеет семантики, которую можно было бы ожидать наивно. - person Alexandre C.   schedule 25.07.2012