I was playing with C++ lambdas and their implicit conversion to function pointers. My starting example was using them as callback for the ftw function. This works as expected.
#include <ftw.h> #include <iostream> using namespace std; int main() { auto callback = [](const char *fpath, const struct stat *sb, int typeflag) -> int { cout << fpath << endl; return 0; }; int ret = ftw("/etc", callback, 1); return ret; }
After modifying it to use captures:
int main() { vector<string> entries; auto callback = [&](const char *fpath, const struct stat *sb, int typeflag) -> int { entries.push_back(fpath); return 0; }; int ret = ftw("/etc", callback, 1); for (auto entry : entries ) { cout << entry << endl; } return ret; }
I got the compiler error:
error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’
After some reading. I learned that lambdas using captures can't be implicitly converted to function pointers.
Is there a workaround for this? Does the fact that they can't be "implicitly" converted mean s that they can "explicitly" converted? (I tried casting, without success). What would be a clean way to modify the working example so that I could append the entries to some object using lambdas?.
A lambda expression with an empty capture clause is convertible to a function pointer. It can replace a stand-alone or static member function as a callback function pointer argument to C API.
Capture clause A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.
Significance of Lambda Function in C/C++ Lambda Function − Lambda are functions is an inline function that doesn't require any implementation outside the scope of the main program. Lambda Functions can also be used as a value by the variable to store.
I just ran into this problem.
The code compiles fine without lambda captures, but there is a type conversion error with lambda capture.
Solution with C++11 is to use std::function
(edit: another solution that doesn't require modifying the function signature is shown after this example). You can also use boost::function
(which actually runs significantly faster). Example code - changed so that it would compile, compiled with gcc 4.7.1
:
#include <iostream> #include <vector> #include <functional> using namespace std; int ftw(const char *fpath, std::function<int (const char *path)> callback) { return callback(fpath); } int main() { vector<string> entries; std::function<int (const char *fpath)> callback = [&](const char *fpath) -> int { entries.push_back(fpath); return 0; }; int ret = ftw("/etc", callback); for (auto entry : entries ) { cout << entry << endl; } return ret; }
Edit: I had to revisit this when I ran into legacy code where I couldn't modify the original function signature, but still needed to use lambdas. A solution that doesn't require modifying the function signature of the original function is below:
#include <iostream> #include <vector> #include <functional> using namespace std; // Original ftw function taking raw function pointer that cannot be modified int ftw(const char *fpath, int(*callback)(const char *path)) { return callback(fpath); } static std::function<int(const char*path)> ftw_callback_function; static int ftw_callback_helper(const char *path) { return ftw_callback_function(path); } // ftw overload accepting lambda function static int ftw(const char *fpath, std::function<int(const char *path)> callback) { ftw_callback_function = callback; return ftw(fpath, ftw_callback_helper); } int main() { vector<string> entries; std::function<int (const char *fpath)> callback = [&](const char *fpath) -> int { entries.push_back(fpath); return 0; }; int ret = ftw("/etc", callback); for (auto entry : entries ) { cout << entry << endl; } return ret; }
Since capturing lambdas need to preserve a state, there isn't really a simple "workaround", since they are not just ordinary functions. The point about a function pointer is that it points to a single, global function, and this information has no room for a state.
The closest workaround (that essentially discards the statefulness) is to provide some type of global variable which is accessed from your lambda/function. For example, you could make a traditional functor object and give it a static member function which refers to some unique (global/static) instance.
But that's sort of defeating the entire purpose of capturing lambdas.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With