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.

 K-ballo27 мая 2012 г., 23:39
В Boost мы имеемprotect для подобных случаев, но, похоже, он не соответствует стандарту.
 Kerrek SB27 мая 2012 г., 23:47
f не являетсяstd::function, а не какой-нибудь неустранимый тип выражения привязки. Вы должны преобразовать его вstd::function в явном виде. Это один из случаев, когда вы не должны использоватьauto.
 ildjarn27 мая 2012 г., 23:53
Увидетьthis answerв частности, часть о предотвращении нетерпеливой оценки (вы не можете изменить тип, потому чтоstd::is_bind_expression<>).
 Lalaland27 мая 2012 г., 23:36
Кажется, работает, когда вы заменяете авто сstd::function<void(int)> для ф.
 coldfix27 мая 2012 г., 23:39
Это не может быть ответом на вашу проблему ... но рассматривали ли вы возможность использования родных лямбда-функций, поставляемых с C ++ 11 (что делает ненужным std :: bind)?

Ответы на вопрос(2)

Решение Вопроса

std::bind выражения, как ихboost::bind предшественники, поддерживают тип операции композиции. Ваше выражение дляw примерно эквивалентно

foo::bar<int>, x, std::placeholders::_1) );

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

Calculate the value of x.bar<int>(y) where y is the first parameter passed into the resulting functor. Pass that result into 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

 28 мая 2012 г., 00:36
Это не основная проблема -std::is_bind_expression<> и его поведение есть.

Ваш ответ на вопрос