std::bind связанной функции
У меня проблемы с обнаружением, почему, черт возьми, это не компилируется. У меня есть лямбда-функция, которая возвращает std::function
основанный на некотором аргументе.
Я сузил свою проблему до этого фрагмента (который не использует лямбда-выражения, но прекрасно воспроизводит мою ошибку):
#include <functional>
#include <iostream>
struct foo {
template<class T>
void bar(T data) {
std::cout << data << "\n";
}
};
void some_fun(const std::function<void(int)> &f) {
f(12);
}
int main() {
foo x;
auto f = std::bind(&foo::bar<int>, x, std::placeholders::_1);
auto w = std::bind(some_fun, f);
w();
}
Призыв к w()
производит один из тех прекрасных выводов ошибок gcc, в которых я не могу понять, что происходит не так. Эта ошибка повторяется gcc 4.6.1:
g++ -std=c++0x test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:20:7: error: no match for call to ‘(std::_Bind<void (*(std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>))(const std::function<void(int)>&)>) ()’
/usr/include/c++/4.6/functional:1130:11: note: candidates are:
/usr/include/c++/4.6/functional:1201:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1215:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1229:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1243:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
Вот, f
должен быть некоторый вызываемый объект, который принимает int в качестве аргумента и вызывает x.bar(int)
используй это. С другой стороны, w
это просто вызываемый объект, который вызывает some_fun(f)
, будучи f
вызываемый объект, упомянутый выше, который имеет подпись, ожидаемую some_fun
параметр.
Я что-то пропустил? Я, наверное, не знаю, как на самом деле смешивать std::bind
а также std::function
,
2 ответа
std::bind
выражения, как их boost::bind
предшественники, поддерживают тип операции композиции. Ваше выражение для w
примерно эквивалентно
auto w=std::bind(some_fun, std::bind(&foo::bar<int>, x, std::placeholders::_1) );
Вложенные связки таким образом интерпретируются как
- Рассчитать стоимость
x.bar<int>(y)
гдеy
это первый параметр, переданный в результирующий функтор. - Передать этот результат в
some_fun
,
Но x.bar<int>(y)
возвращает void, а не любой тип функции. Вот почему это не компилируется.
Как указывает К-балл, с boost::bind
Вы можете решить эту проблему с boost::protect
, Как указывают Kerrek SB и ildjarn, один из способов решения этой проблемы: не использовать auto
за f
, Ты не хочешь f
иметь тип выражения привязки. Если f
имеет какой-то другой тип, то std::bind
не будет пытаться применять правила композиции функций. Вы могли бы, например, дать f
тип std::function<void(int)>
:
std::function<void(int)> f = std::bind(&foo::bar<int>, x, std::placeholders::_1);
auto w = std::bind(some_fun, f);
поскольку f
буквально не имеет типа выражения привязки, std::is_bind_expression<>::value
будет ложным на f
и так std::bind
выражение во второй строке будет просто передавать значение дословно, а не пытаться применять правила композиции функций.
some_fun
хочет аргумент типа const std::function<void(int)> &
,
std:: bind возвращает "объект функции неопределенного типа T" (смотрите предоставленную ссылку, раздел "Возвращаемое значение"), который вы пытаетесь передать в качестве аргумента some_fun.
Кажется, это вызывает проблемы, потому что этот тип аргумента не ожидается.
Посмотрите на: http://en.cppreference.com/w/cpp/utility/functional/bind