использовать std::bind с перегруженными функциями

Я не могу понять, как связать параметр с перегруженной функцией, используя std::bind. Почему-то std::bind не может вывести перегруженный тип (для его параметров шаблона). Если я не перегружаю функцию, все работает. Код ниже:

#include <iostream>
#include <functional>
#include <cmath>

using namespace std;
using namespace std::placeholders;

double f(double x) 
{
    return x;
}

// std::bind works if this overloaded is commented out
float f(float x) 
{
    return x;
}

// want to bind to `f(2)`, for the double(double) version

int main()
{

    // none of the lines below compile:

    // auto f_binder = std::bind(f, static_cast<double>(2));

    // auto f_binder = bind((std::function<double(double)>)f, \
    //  static_cast<double>(2));

    // auto f_binder = bind<std::function<double(double)>>(f, \
    //  static_cast<double>(2));

    // auto f_binder = bind<std::function<double(double)>>\
    // ((std::function<double(double)>)f,\
    //  static_cast<double>(2));

    // cout << f_binder() << endl; // should output 2
}

Насколько я понимаю, std::bind не может как-то вывести параметры своего шаблона, так как f перегружен, но как их указать не могу понять. Я пробовал 4 возможных способа в коде (закомментированные строки), ни один не работает. Как указать тип функции для std::bind? Любая помощь высоко ценится!


person vsoftco    schedule 21.07.2014    source источник
comment
Просто обратите внимание, что у std::function та же проблема, что и у std::bind. Он не может знать, какой f вы имеете в виду.   -  person chris    schedule 22.07.2014
comment
@chris, верно, теперь это имеет смысл, спасибо   -  person vsoftco    schedule 22.07.2014
comment
Кстати, 2. (или 2.0) — это (буквальное) double, которое вы можете написать вместо преобразования int 2 в double.   -  person Jarod42    schedule 22.07.2014
comment
@ Jarod42 Jarod42 да, я знаю, у меня был static_cast остаток от реального кода, который я изменил, чтобы он соответствовал минимальному примеру.   -  person vsoftco    schedule 22.07.2014
comment
@ Jarod42, вы также можете использовать только 2. Поскольку std::bind знает, что функция принимает double, int можно преобразовать.   -  person chris    schedule 22.07.2014
comment
Одно из преимуществ лямбда-выражений по сравнению с std::bind заключается в том, что лямбда-выражениям не нужно отделять имена от разрешения перегрузки. []{ return f(2.0); } гораздо понятнее, чем std::bind(static_cast<double(*)(double)>(f), 2.0).   -  person Casey    schedule 22.07.2014
comment
@Кейси: Ага. std::bind в основном устарел в тот момент, когда он был стандартизирован. Однажды я видел действительный вариант использования, я даже не могу вспомнить, что это было сейчас.   -  person Benjamin Lindley    schedule 22.07.2014
comment
@Casey, это действительно правда, я только учился использовать bind.   -  person vsoftco    schedule 22.07.2014
comment
@BenjaminLindley, bind имеет некоторые преимущества, например, вы можете привязываться к функторам, у которых есть состояние, что нелегко сделать с помощью лямбда   -  person vsoftco    schedule 22.07.2014
comment
@vsoftco: я не понимаю, что вы имеете в виду. Лямбды также могут иметь состояние. У вас есть пример?   -  person Benjamin Lindley    schedule 22.07.2014
comment
@BenjaminLindley, подумайте о функторе-генераторе, который принимает, например, начальную точку int x=0 в качестве параметра ctor по умолчанию, а затем для каждого вызова выводит увеличенную версию, например 1, 2, 3 и т. д. Вы можете сделать это с помощью лямбда, но должны поддерживать состояние снаружи (во внешней переменной), фиксировать его по ссылке или по значению и использовать mutable, так что это более беспорядочно. А если у вас есть слой лямбд внутри лямбд, то все становится очень сложно.   -  person vsoftco    schedule 22.07.2014
comment
@BenjaminLindley, хорошо, в C++14 вы можете инициализировать лямбда-захваты, и это решает проблему, то есть вы можете сделать что-то вроде auto generator_int = [x = 0]() mutable ->int {return x++;};   -  person vsoftco    schedule 22.07.2014


Ответы (1)


Вы можете использовать:

auto f_binder = std::bind(static_cast<double(&)(double)>(f), 2.);

or

auto f_binder = bind<double(double)>(f, 2.);

В качестве альтернативы можно использовать лямбда:

auto f_binder = []() {
    return f(2.);     // overload `double f(double)` is chosen as 2. is a double.

};
person Jarod42    schedule 21.07.2014
comment
Да, это единственное, что я не пробовал :) Я почему-то думал, что пробовал вторую версию, но не стал, так как обе работают. PS: указатель на функцию тоже работает. Спасибо! - person vsoftco; 22.07.2014
comment
Второй синтаксис довольно чистый, мне нравится. - person Germán Diago; 22.07.2014