A std::function
- это не лямбда, а лямбда - это не std::function
.
Лямбда - это анонимный тип с operator()
и некоторыми другими второстепенными утилитами. Ваш
auto foo = [](int i) {
std::cout << i << std::endl;
};
является сокращением для
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
очень приблизительно (есть фактический указатель преобразования в функцию и некоторые другие шумы, которые я не буду освещать).
Но обратите внимание, что не наследуется от std::function<void(int)>
.
Лямбда не будет выводить параметры шаблона std::function
, потому что это не связанные типы. Вывод типа шаблона - это точное сопоставление с типами передаваемых аргументов и их базовых классов. Он не пытается использовать преобразование любого вида.
A std::function<R(Args...)>
- это тип, который может хранить все, что можно копировать, может вызываться со значениями, совместимыми с Args...
, и возвращает что-то, совместимое с R
.
Таким образом, std::function<void(char)>
может хранить что угодно , которое может быть вызвано с помощью char
. Поскольку int
функции могут быть вызваны с помощью char
, это работает.
Попробуйте:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
std::function
делает это некоторым преобразованием из своей подписи в хранимую в нем функцию вызова.
Самое простое решение:
template <class F, class T>
void call(F f, T v) {
f(v);
}
теперь, в крайне редких случаях, вам действительно нужна подпись. Вы можете сделать это в c ++ 17 :
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Наконец, ваш call
является ограниченной версией std::invoke
от c ++ 17 . Подумайте об этом; если нет, используйте версии с бэкпортом.