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

Вложенные связки таким образом интерпретируются как

  1. Рассчитать стоимость x.bar<int>(y) где y это первый параметр, переданный в результирующий функтор.
  2. Передать этот результат в 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

Другие вопросы по тегам