我正在使用cURL通过http下载文件。 cURL需要一个回调来处理数据,我在我的类中有一个回调,我正在使用std :: bind和std :: function的组合来创建一个具有正确类型的函数。
size_t NetworkResource::writeFunction(char *ptr,size_t size,size_t nmemb,void *userdata)
{
...
}
void NetworkResource::loadFunction(void)
{
using namespace std::placeholders;
typedef size_t CurlCallback(char*,size_t,size_t,void*);
auto function=std::function<CurlCallback>(std::bind(&NetworkResource::writeFunction,this,_1,_2,_3,_4)).target<CurlCallback*>();
CURL *curl=curl_easy_init();
CURLcode err;
...
err=curl_easy_setopt(curl,CURLOPT_WRITEDATA,nullptr);
if(err!=CURLE_OK) std::cout<<curl_easy_strerror(err)<<std::endl;
err=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,*function);
if(err!=CURLE_OK) std::cout<<curl_easy_strerror(err)<<std::endl;
...
}
问题是函数为null。根据文档,当返回的类型与函数的目标类型不匹配时会发生这种情况,但据我所知它们确实匹配。
答案 0 :(得分:1)
auto function = std::function<CurlCallback>(
std::bind(&NetworkResource::writeFunction,this,
_1,_2,_3,_4)).target<CurlCallback*>();
您构建的std::function
对象将在上面的表达式末尾被销毁,变量function
将指向无效的内存,调用{ {3}}按预期工作。在这种情况下,它没有,函数调用返回nullptr
。
这是因为std::function
的目标函数类型与CurlCallback
的类型不同。 std::function::target
显示了该调用有效的情况,以及失败的情况。
您的问题可以在不使用std::function
的情况下解决。
根据This example的文档,当第二个参数为CURLOPT_WRITEFUNCTION
时,第三个参数应该是指向具有签名的函数的指针
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);
可以通过调用curl_easy_setopt
来设置最后一个参数userdata
。使用此指针传递指向NetworkResource
实例(this
指针)的指针。
对于write_callback
,创建一个执行所需功能的静态成员函数。
class NetworkResource
{
// ...
static size_t writeFunction(char *ptr,size_t size,size_t nmemb,void *userdata);
};
size_t NetworkResource::writeFunction(char *ptr,size_t size,size_t nmemb,void *userdata)
{
// userdata points to the NetworkResource instance
auto res = static_cast<NetworkResource *>(userdata);
// use res and the remaining function arguments to handle the call
}
void NetworkResource::loadFunction(void)
{
CURL *curl=curl_easy_init();
CURLcode err;
...
err=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,&NetworkResource::writeFunction);
if(err!=CURLE_OK) std::cout<<curl_easy_strerror(err)<<std::endl;
err=curl_easy_setopt(curl,CURLOPT_WRITEDATA,static_cast<void *>(this));
if(err!=CURLE_OK) std::cout<<curl_easy_strerror(err)<<std::endl;
...
}
答案 1 :(得分:0)
今天我遇到了这个问题,我可以建议您一个解决方案: 这是我的演示
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <thread>
#include <unistd.h>
#include <string.h>
#include <functional>
using namespace std;
class foo {
public:
virtual int sum(int a, int b) { return -1; };
};
class bar : public foo{
public:
virtual int sum(int a, int b) override;
};
int bar::sum(int a, int b) {
return a + b;
}
int main() {
bar *b = new bar();
std::function<int(int, int)> f = std::bind(&bar::sum, b, std::placeholders::_1, std::placeholders::_2);
printf("result : %d\n", f(1, 3));
printf("result : %s\n", f.target_type().name());
printf("null : %d\n", (*f.target<int(int, int)>())(1, 2));
printf("null : %d\n", f);
return 0;
}
在此演示中,如果您将std::function
类型为int(int,int)写入
std::function<int(int, int)>
返回类型必须为null,因为int(int, int)
不等于内部类型
要获取std::function
的内部类型,您应该首先使用target_type().name()
,如下所示:
printf("%s\n", f.target_type().name());
结果是:
St5_BindIFSt7_Mem_fnIM3barFiiiEEPS1_St12_PlaceholderILi1EES6_ILi2EEEE
然后,您可以使用c++filt
来解析该符号,如下所示:
c++filt -t St5_BindIFSt7_Mem_fnIM3barFiiiEEPS1_St12_PlaceholderILi1EES6_ILi2EEEE
结果是:
std::_Bind<std::_Mem_fn<int (bar::*)(int, int)> (bar*, std::_Placeholder<1>, std::_Placeholder<2>)>
上面的符号就是您应该在std::function<...>
中写的内容,因此最终代码如下:
int main() {
bar *b = new bar();
std::function<int(int, int)> f = std::bind(&bar::sum, b, std::placeholders::_1, std::placeholders::_2);
printf("result : %d\n", f(1, 3));
printf("result : %s\n", f.target_type().name());
printf("null : %d\n", (*f.target<std::_Bind<std::_Mem_fn<int (bar::*)(int, int)> (bar*, std::_Placeholder<1>, std::_Placeholder<2>)>>())(1, 2));
printf("null : %d\n", f);
return 0;
}