It's because a lambda function is not a std::function<...>. The type of
auto lambda = [](const std::string& s) { return std::stoi(s); };
is not std::function<int(const std::string&)>, but something unspecified which can be assigned to a std::function. Now, when you call your method, the compiler complains that the types don't match, as conversion would mean to create a temporary which cannot bind to a non-const reference.
This is also not specific to lambda functions as the error happens when you pass a normal function. This won't work either:
int f(std::string const&) {return 0;}
int main()
{
std::vector<int> vec;
C<int> c;
c.func(vec, f);
}
You can either assign the lambda to a std::function
std::function<int(const std::string&)> lambda = [](const std::string& s) { return std::stoi(s); };
,change your member-function to take the function by value or const-reference or make the function parameter a template type. This will be slightly more efficient in case you pass a lambda or normal function pointer, but I personally like the expressive std::function type in the signature.
template<typename T>
class C{
public:
void func(std::vector<T>& vec, std::function<T( const std::string)> f){
//Do Something
}
// or
void func(std::vector<T>& vec, std::function<T( const std::string)> const& f){
//Do Something
}
// or
template<typename F> func(std::vector<T>& vec, F f){
//Do Something
}
};
Answer from Jens on Stack Overflowc++ - I cannot pass lambda as std::function - Stack Overflow
When to use a lambda over a function pointer?
c++ - How to convert a lambda to an std::function using templates - Stack Overflow
lambda to std::function template - C++ Forum
Videos
It's because a lambda function is not a std::function<...>. The type of
auto lambda = [](const std::string& s) { return std::stoi(s); };
is not std::function<int(const std::string&)>, but something unspecified which can be assigned to a std::function. Now, when you call your method, the compiler complains that the types don't match, as conversion would mean to create a temporary which cannot bind to a non-const reference.
This is also not specific to lambda functions as the error happens when you pass a normal function. This won't work either:
int f(std::string const&) {return 0;}
int main()
{
std::vector<int> vec;
C<int> c;
c.func(vec, f);
}
You can either assign the lambda to a std::function
std::function<int(const std::string&)> lambda = [](const std::string& s) { return std::stoi(s); };
,change your member-function to take the function by value or const-reference or make the function parameter a template type. This will be slightly more efficient in case you pass a lambda or normal function pointer, but I personally like the expressive std::function type in the signature.
template<typename T>
class C{
public:
void func(std::vector<T>& vec, std::function<T( const std::string)> f){
//Do Something
}
// or
void func(std::vector<T>& vec, std::function<T( const std::string)> const& f){
//Do Something
}
// or
template<typename F> func(std::vector<T>& vec, F f){
//Do Something
}
};
It's because the argument (std::function) is a reference. It should be:
void func(std::vector<T>& vec, std::function<T(const std::string&)> f)
^ ^
|
f not a reference
So that the argument can be converted to the parameter type.
Also, the type of the function should match. I.e. it should accept a string reference.
Question seems simple enough.
I've never really understood then point of lambdas. To me the code seems messy, why not use a function pointer instead?
You can't pass a lambda function object as an argument of type std::function<T> without explicitly specifying the template argument T. Template type deduction tries to match the type of your lambda function to the std::function<T> which it just can't do in this case - these types are not the same. Template type deduction doesn't consider conversions between types.
It is possible if you can give it some other way to deduce the type. You can do this by wrapping the function argument in an identity type so that it doesn't fail on trying to match the lambda to std::function (because dependent types are just ignored by type deduction) and giving some other arguments.
template <typename T>
struct identity
{
typedef T type;
};
template <typename... T>
void func(typename identity<std::function<void(T...)>>::type f, T... values) {
f(values...);
}
int main() {
func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8);
return 0;
}
This is obviously not useful in your situation though because you don't want to pass the values until later.
Since you don't want to specify the template parameters, nor do you want to pass other arguments from which the template parameters can be deduced, the compiler won't be able to deduce the type of your std::function argument.
TL;DR: What you ask can be done using CTAD, a feature that enables you to create an std::function of the expected type, right at the call site without spelling out the template arguments:
foo(std::function([](int arg){ return Bar{}; }));
// ^^^^^^^^^^^^^ constructor call w/o templates
// std::function<Bar(int)> will be auto-deduced
Demo
If you are interested on how to emulate the mechanics of such a deduction, or need to work with a pre c++17 compiler, check the rest of the answer.
You can use a dedicated/retrospective cast. Once you have a tool like this
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
you can say FFL() to all lambda types to have them converted to what would be the correct version of std::function
template <typename... Args> void Callback(std::function<void(Args...)> f){
// store f and call later
}
int main()
{
Callback(FFL([](int a, float b){
// do something
}));
return 0;
}
Display