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?
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.