Понимание std::function и std::bind

Я играл с std::function и std::bind и заметил кое-что неинтуитивное, и я хотел бы понять это лучше.

Например:

void fun()
{
}

void hun(std::string) 
{ 
}

int main()
{

   function<void(int)> g = &fun; //This fails as it should in my understanding.

   function<void(int)> f = std::bind(fun); //This works for reasons unknown to me     
   function<void(int, std::string)> h = std::bind(hun); //this doesn't work

return 0;
}

Как можно связать function<void(int)> с функцией void(). Затем я мог бы вызвать f(1) и получить fun(). Я хотел бы понять, как это делается. Зайдя внутрь реализации Microsoft Visual Studio 2012, я потерялся в море нечитаемых макросов. поэтому я задаю этот вопрос здесь.


person Alex    schedule 23.04.2013    source источник
comment
Я использую версию vs2012 Express.   -  person Alex    schedule 23.04.2013
comment
Можете ли вы порекомендовать такой сайт, пожалуйста?   -  person Alex    schedule 23.04.2013
comment
Компилируется с помощью clang и g++. +1, интересная ситуация.   -  person awesoon    schedule 23.04.2013
comment
@KerrekSB: Это правильное поведение - мне лучше задаться вопросом, с какой stdlib вы тестировали версию std::bind(fun), потому что она содержит ошибки. :)   -  person Xeo    schedule 23.04.2013
comment
возможный дубликат std::function и поведение std::bind   -  person ecatmur    schedule 23.04.2013
comment
@pacificator: в прошлом использовались ideone и liveworkspace. У них хороший выбор компиляторов.   -  person Kerrek SB    schedule 23.04.2013
comment
@Xeo: Извините, я виноват, я испортил свой тестовый пример!   -  person Kerrek SB    schedule 23.04.2013
comment
см. stackoverflow.com/a/16172580/981959 для ответа   -  person Jonathan Wakely    schedule 23.04.2013


Ответы (2)


Если вы не используете заполнители аргументов (_1, _2, ...), то любые аргументы, переданные объекту функции, возвращенному из std::bind, будут просто отброшены. С:

std::function<void(int)> f = std::bind(fun, std::placeholders::_1);

Я получаю (длинную и уродливую) ошибку, как и ожидалось.

Для тех, кто интересуется Standardese:

§20.8.9.1.2 [func.bind.bind]

template<class F, class... BoundArgs>
*unspecified* bind(F&& f, BoundArgs&&... bound_args);

p3 Возвращает: Оболочка переадресации вызова g со слабым типом результата (20.8.2). Эффект g(u1, u2, ..., uM) должен быть INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type), где cv представляет cv-квалификаторы g, а значения и типы связанных аргументов v1, v2, ..., vN определяются, как указано ниже< /сильный>.

p10 Значения связанных аргументов v1, v2, ..., vN и соответствующих им типов V1, V2, ..., VN зависят от типов TiD, полученных из вызова bind, и cv-квалификаторов cv > оболочки вызова g следующим образом:

  • если TiD равно reference_wrapper<T>, аргумент равен tid.get(), а его тип Vi равен T&;
  • если значение is_bind_expression<TiD>::value равно true, аргумент равен tid(std::forward<Uj>(uj)...), а его тип Vi равен result_of<TiD cv (Uj...)>::type;
  • если значение j из is_placeholder<TiD>::value не равно нулю, аргумент равен std::forward<Uj>(uj), а его тип Vi равен Uj&&;
  • в противном случае значение равно tid, а его тип Vi равен TiD cv &.
person Xeo    schedule 23.04.2013
comment
Более того, даже если std::function‹void(int)› f = std::bind(fun); компилирует. На самом деле невозможно вызвать f: f(); не удается скомпилировать. - person Peter R; 23.04.2013
comment
@PeterR: Очевидно, потому что подпись f требует одного аргумента. :) - person Xeo; 23.04.2013

Оболочка переадресации вызовов, сгенерированная вызовом шаблона функции bind, может принимать любое количество дополнительных параметров; они будут проигнорированы. Эффективная арность и минимальная подпись выражения bind определяются placeholder, используемыми в его построении, и с какими вызываемыми аргументами они связаны.

person ecatmur    schedule 23.04.2013