I have the following code:
std::string stream;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, & stream);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void *buffer, size_t size, size_t count, std::string *stream) -> size_t {
auto s_size = size * count;
stream->append((char *)buffer, 0, s_size);
return s_size;
});
It compiles and it crashes. If I replace the lambda by a function, it works fine:
static size_t _writefunction(void *buffer, size_t size, size_t count, std::string *stream) {
auto s_size = size * count;
stream->append((char *)buffer, 0, s_size);
return s_size;
}
Is there any way to use a lambda instead of a separated function?
>Solution :
curl_easy_setopt is documented with the signature
CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
where the parameter is allowed to be one of several types depending on the option. Clearly, (as a C API, where C has no overloading) it must be doing something strange, and this is borne out by looking at the source, where we see curl_easy_setopt is implemented with varargs.
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
So the problem with passing a lambda to curl_easy_setopt is that it is getting passed in as is, since curl_easy_setopt says it can take objects of any type. The actual object represented by a lambda expression is just a struct of the captures; in this case, you’re just passing an empty struct object to curl_easy_setopt when it is expecting a function pointer. Chaos ensues.
Lambdas with no captures may be explicitly converted to function pointers by using unary +.
// v one char fix!
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +[](void *buffer, size_t size, size_t count, std::string *stream) -> size_t {
auto s_size = size * count;
stream->append((char *)buffer, 0, s_size);
return s_size;
});
This conversion can also happen implicitly, but curl_easy_setopt doesn’t provide any type information and thus doesn’t trigger the conversion automatically.