我一直在研究 libcurl 庫,我需要為 API 提供一個回呼函式,說明它應該如何處理接收到的資料。我嘗試將此回呼函式作為 lambda 提供給它,它給了我訪問沖突錯誤,而當我在其他地方定義函式后提供與函式指標相同的函式時,它作業正常!我想知道兩者之間有什么區別,因為我認為它們是同一件事。
以下部分中使用的代碼來自https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html,它是 libcurl 的檔案。
這是我向其發送 lambda 函式的代碼(這會導致訪問沖突錯誤):
int main() {
// Irrelevant initial code...
struct memory {
char* response;
size_t size;
} chunk = { 0 };
curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void*) &chunk);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, // I define a lambda function for the callback...
[](void* data, size_t size, size_t nmemb, void* chunk) -> size_t {
cout << "This function will never get called.. :(" << endl;
size_t realSize = size * nmemb;
memory* mem = (memory*) chunk;
char* ptr = (char*) realloc(mem->response, mem->size realSize 1);
if (ptr == NULL) return 0;
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, realSize);
mem->size = realSize;
mem->response[mem->size] = 0;
return realSize;
});
CURLcode success = curl_easy_perform(handle);
return 0;
}
這里從未呼叫過 lambda 函式,因此該行This function will never get called.. :(永遠不會顯示在控制臺中。它在第 563 行名為 sendf.c 的檔案中的 libcurl 庫中給出了訪問沖突錯誤。
現在這是同樣的事情,但我在外面定義了函式:
struct memory {
char* response;
int size;
};
// defined the callback function outside...
size_t cb(void* data, size_t size, size_t nmemb, void* userp)
{
cout << "Working!" << endl;
size_t realsize = size * nmemb;
memory* mem = (memory*)userp;
char* ptr = (char*) realloc(mem->response, mem->size realsize 1);
if (ptr == NULL)
return 0;
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, realsize);
mem->size = realsize;
mem->response[mem->size] = 0;
return realsize;
}
int main() {
// Irrelevant initial code...
memory chunk = { 0 };
curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void*) &chunk);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, cb);
CURLcode success = curl_easy_perform(handle);
return 0;
}
這個有效,它顯示Working!在控制臺中。
我不明白為什么這兩個不同,為什么其中一個有效而另一個無效。也可以使用 lambda 函式方法來完成這項作業,因為我認為它看起來更整潔。
uj5u.com熱心網友回復:
編輯
@user17732522 的主要道具提醒我你可以通過簡單地使用作為前綴來獲得相同的效果而無需所有戲劇性 lambda。對我來說,撰寫合理的答案為時已晚。Sry我完全隔開。
原來的
curl_easy_setopt接受一個可變引數堆疊,并根據正在建立的選項將它們剝離到它們的子組件。如果您深入了解 curl 標頭,您會發現:
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
可變引數很重要。這將非常接近任何東西,并期望它成為它的原生型別。那么......那個lambda的本機型別是什么。一種“騙子”的判斷方式是使用帶有漂亮列印選項的通用模板來宣布在擴展中接收到的型別(這聽起來令人困惑,我保證不會在一分鐘內完成):
#include <iostream>
template<class T>
void foo(T&&)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main()
{
foo([](void *, size_t , size_t , void *) -> size_t
{
return size_t();
});
return 0;
}
輸出
void foo(T &&) [T = (lambda at main.cpp:11:9)]
所以,是的,它很高興地將一個“lambda”推入變數 arg 串列中。合法地轉換為等效的函式指標型別(我們可以這樣做,因為 lambda 是非捕獲的),給我們:
#include <iostream>
template<class T>
void foo(T&&)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main()
{
foo(static_cast<size_t (*)(void *, size_t, size_t, void *)>(
[](void *, size_t , size_t , void *) -> size_t
{
return size_t();
}));
return 0;
}
輸出
void foo(T &&) [T = unsigned long (*)(void *, unsigned long, unsigned long, void *)]
現在一個實際的函式指標被推到 arg 串列中,這是預期的CURLOPT_WRITEFUNCTION
注意:如果背景關系呼叫函式指標期望,則可以在函式指標背景關系中隱式使用非捕獲 lambda。例如,以下不需要強制轉換;轉換是隱式的,因為 lambda 是非捕獲的,因此符合條件,并且背景關系專門呼叫相應匹配的函式指標:
#include <iostream>
void bar(size_t (*)(void *, size_t, size_t, void *))
{
}
int main()
{
bar([](void *, size_t , size_t , void *) -> size_t
{
return size_t();
});
return 0;
}
簡短的回答是:curl_easy_setopt可變引數將您的 lambda 用作 lambda;不是作為函式指標。如果在這種情況下你想要一個函式指標(你確實想要),你需要“哄”它提交。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/505194.html
