第13章 网络 13.6.3 实现多样化回调 02用模板实现更强大的回调 绑定Lambda表达式

下面是《白话C++练武篇》书中658页,访问ftp服务器得到报头数据的程序

#include <curl/curl.h>
#include <iostream>

using namespace std;

size_t to_stream(char* data, size_t size, size_t nmemb, void* userdata)
{
    ostream& p = * static_cast <ostream *> (userdata);

    //从一个C风格的字符串构造字符串,但最多取n个字符或遇到'\0'
    std::string line(data, size*nmemb);
    //将字符串写入到指定的ostream对象中
    p << line;

    return size*nmemb;
}

int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());

    /*在libcurl库中,CURLOPT_HEADERFUNCTION是一个选项,它允许你设置一个回调函数来处理接收到的HTTP头信息。*/
    curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, to_stream);

    /*libcurl常数CURLOPT_HEADERDATA是libcurl的一个选项,它用于传递指针给libcurl*/
    curl_easy_setopt(handle, CURLOPT_HEADERDATA, static_cast <void*> (&cout));

    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();

    return 0;
}

26行,使用to_stream函数,被设置为访问报头数据,需要的回调函数。它将访问得到的网络数据打印出来。

29行,为了将报头数据打印到控制台,将cout传递给了to_stream, 因为仅仅to_stream是不够的,还需要cout的辅助。

运行结果为。

下面我们使用模板技术实现更强大的回调方式

#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <functional>

using namespace std;

struct CURLFunctionHelper
{
    CURLFunctionHelper(CURL* curl, CURLoption opt_function, CURLoption opt_data)
    {
        curl_easy_setopt(curl, opt_function, inner_function);
        curl_easy_setopt(curl, opt_data, this);
    }

    template <typename Fn>//使用模板技术

    void Bind(Fn&& fn) //fn的类型是个右值
    {
        //对象fn并非简单复制给了_callback,而是转移给了_callback,即:若是fn含有指针
        //类型的成员,则指针复制给_callback, fn的指针成员被赋值为nullptr
        _callback = std::move(fn);
    }

private:
    //简化function类型表达
    typedef std::function <size_t(char*, size_t, size_t)> CURLCallback;
    //负责转接的静态成员函数
    static size_t inner_function(char* data
                                 , size_t size, size_t nmemb
                                 , void* userdata)
    {
        auto self = static_cast <CURLFunctionHelper*> (userdata);
        return self->_callback(data, size, nmemb); //在此处转发
    }

    //function<>成员
    CURLCallback _callback;
};

int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());

    //构造一个CURLFunctionHelper对象,指明配置项和HEADER相关,在构造函数中,完成handle的设置
    CURLFunctionHelper helper(handle, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA);

    //绑定一个lambda表达式,注意它的入参和返回值
    helper.Bind([](char* data, size_t size, size_t nmemb)->size_t
            {
                std::string line(data, size*nmemb);
                cout << line;
                return size*nmemb;
            });

    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();
    return 0;
}

50行,声明一个helper对象,该对象的构造函数中,完成了回调函数的设置

          其中,13行,将静态成员函数inner_function设置为回调函数,而inner_function中需要访问非静态成员_call_back, 这需要一个CURLFunctionHelper对象,所以14行,将this对象传递给了inner_function。

53行,调用helper的Bind() 成员函数,Bind()函数,通过转移的方式,将Lambda表达式

[](char* data, size_t size, size_t nmemb)->size_t
            {
                std::string line(data, size*nmemb);
                cout << line;
                return size*nmemb;
            }

赋给了_callback成员。

实际执行过程,将执行30行的静态成员函数inner_function,而inner_function中,self是14行传递过来的this,35行,调用_callback, 而_callback就是Bind函数转移过来的Lambda表达式,从而实现了对ftp报头数据的打印。

运行效果如下图:

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值