Использовать 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
? Любая помощь высоко ценится!
2 ответа
Вы можете использовать:
auto f_binder = std::bind(static_cast<double(&)(double)>(f), 2.);
или же
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.
};
Имя перегруженной функции можно использовать только в определенных контекстах, которые позволяют вывести единственную желаемую перегрузку. Например, перегруженное имя можно использовать в качестве аргумента static_cast (как в ответе @Jarod42) или как правую часть присваивания:
void foo() { std::cout << "foo()" << std::endl; }
void foo(int, float) { std::cout << "foo(int, float)" << std::endl; }
int main() {
/* foo denotes all overloaded foo-s. ptr denotes only one.
* foo(0, 0) and foo() are both valid
* ptr(0, 0) is valid, ptr() is not */
void (*ptr)(int, float) = foo;
auto f = std::bind(ptr, 0, 0);
f();
auto g = std::bind(static_cast<void (*)(int, float)>(foo), 0, 0);
g();
}
Как только выбирается какая-либо перегрузка, вы получаете обычный указатель на функцию, который хорошо работает с std::bind/std::function/etc.
Весь список разрешенных контекстов можно посмотреть здесь .
Немного синтаксического сахара
Если вам часто приходится использовать перегрузки с функциями шаблона, такими как std::bind, вы можете применить подход, используемый в классе QOverload в QT, который предоставляет для этого удобный и понятный интерфейс. Он работает только с перегруженными функциями-членами из коробки, но может быть легко расширен и для функций, не являющихся членами.
Вот короткая демонстрация из документации QT:
struct Foo {
void overloadedFunction();
void overloadedFunction(int, const QString &);
};
... qOverload<>(&Foo::overloadedFunction)
... qOverload<int, const QString &>(&Foo::overloadedFunction)
В отличие от static_cast, вам не нужно явно указывать тип возвращаемого значения, потому что не может быть двух функций с одинаковыми параметрами, но разными типами возвращаемого значения или именем класса.