std :: function.target返回null

时间:2014-06-23 20:34:22

标签: c++ c++11 curl

我正在使用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。根据文档,当返回的类型与函数的目标类型不匹配时会发生这种情况,但据我所知它们确实匹配。

2 个答案:

答案 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;
 }