seastar中apply模板的实现

简介: 我在阅读seastar的源码时(这并不代表我熟悉seastar),偶然发现了seastar把tuple里的每一个element传给一个函数作为参数,这让我很好奇它是如何实现的,让我不自量力地分析一下。 seastar有个头文件apply.hh包含如下代码: ``` namespace seastar {

我在阅读seastar的源码时(这并不代表我熟悉seastar),偶然发现了seastar把tuple里的每一个element传给一个函数作为参数,这让我很好奇它是如何实现的,让我不自量力地分析一下。

seastar有个头文件apply.hh包含如下代码:

namespace seastar {                                                             
                                                                                
template <typename Func, typename Args, typename IndexList>                     
struct apply_helper;                                                            
                                                                                
template <typename Func, typename Tuple, size_t... I>                           
struct apply_helper<Func, Tuple, std::index_sequence<I...>> {                   
    static auto apply(Func&& func, Tuple args) {                                
        return func(std::get<I>(std::forward<Tuple>(args))...);                 
    }                                                                           
};                                                                              
                                                                                
template <typename Func, typename... T>                                         
inline                                                                          
auto apply(Func&& func, std::tuple<T...>&& args) {                              
    using helper = apply_helper<Func, std::tuple<T...>&&, std::index_sequence_for<T...>>;
    return helper::apply(std::forward<Func>(func), std::move(args));            
}                                                                               
                                                                                
template <typename Func, typename... T>                                         
inline                                                                          
auto apply(Func&& func, std::tuple<T...>& args) {                               
    using helper = apply_helper<Func, std::tuple<T...>&, std::index_sequence_for<T...>>;
    return helper::apply(std::forward<Func>(func), args);                       
}                                                                               
                                                                                
template <typename Func, typename... T>                                         
inline                                                                          
auto apply(Func&& func, const std::tuple<T...>& args) {                         
    using helper = apply_helper<Func, const std::tuple<T...>&, std::index_sequence_for<T...>>;
    return helper::apply(std::forward<Func>(func), args);                       
}                                                                               
           

以上这段代码实现的功能是把通过tuple打包的各个element数据拆开,并作为一个个参数去调用其他函数,下面展示如何使用它:


void print(int i, double f)
{
    std::cout << "i:" << i << " f:" << f << '\n';
}

int main()
{
    std::tuple<int, double> values(1, 2.3); //对数据1和2.3打包
    apply(print, values); //调用 print, 把1和2.3作为调用参数
}

以上就是把值1和2.3打包,然后通过apply把这些打包的参数通过apply来调用函数print。

上面seastar中apply_helper的主模板没有定义,只是写了一个声明:

template <typename Func, typename Args, typename IndexList>                     
struct apply_helper;     

然后就是准对第三个模板参数做了部分特化,这第三个参数用的到就是index_sequence模板实例类型:

template <typename Func, typename Tuple, size_t... I>                           
struct apply_helper<Func, Tuple, std::index_sequence<I...>> {  
static auto apply(Func&& func, Tuple args) {                                
        return func(std::get<I>(std::forward<Tuple>(args))...);                 
    }                                                                           
};     
    

这个apply静态函数的秘密就是利用index_sequence模板实例化时携带的非类型可变参数列表"I...",利用编译器自动对可变参数列表的展开,把这些参数列表里的一个个参数去调用std::get,而这个get则是获取tuple里由Index指定的element。Index是一个整形值。注意调用的方式,get后面跟随一个...操作符:

std::get<I>(std::forward<Tuple>(args))...

它把index_sequence实例化的参数列表I的每一个参数去分别调用get,由编译器自动重复这个过程。

例如,如果你有index_sequence<1,2,3>这个模板实例定义的类型,那么

func(std::get<I>(std::forward<Tuple>(args))...)

的意思就是:

func(std::get<1>(std::forward(args)), std::get<2>(std::forward(args)), std::get<3>(std::forward(args)))

STL中的index_sequence_for模板的定义

template<typename... _Types>                                                  
    using index_sequence_for = make_index_sequence<sizeof...(_Types)>;

具体细节我不多讲了,有兴趣可以去看libstdc++头文件的实现,位于utility头文件。
它的作用就是为给定的一个参数列表,实例化模板index_sequence得到一个新的类型,该类型的模板参数是一系列索引号列表:

例如 index_sequence_for生成一个实例化类型:
index_sequence<0,1,2>。
这样0,1,2这个参数列表就可以用在apply一系列的模板中。

由于在apply代码中,模板演绎时tuple始终不丢弃,所以实际上我们在展开这些tuple element作为函数调用的参数时,只需要一系列序号让编译器去重复调用get模板,这就是index_sequence的作用所在。

目录
相关文章
|
6月前
|
Kubernetes 负载均衡 应用服务中间件
k8s学习-Ingress(安装、模板、创建、删除)
k8s学习-Ingress(安装、模板、创建、删除)
252 0
|
3月前
|
运维 Prometheus 监控
今天在集群中创建yaml,使用create就创建成功,apply就创建失败原因分析。
今天在集群中创建yaml,使用create就创建成功,apply就创建失败原因分析。
|
4月前
|
缓存 Serverless API
函数计算产品使用问题之没有s.yaml文件,修改代码如何重新部署
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
运维 负载均衡 Serverless
函数计算产品使用问题之yaml如果写多个function,可不可以yaml在构建的时候能构建多个函数
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
5月前
|
XML 数据格式
yaml基本语法和yaml数据格式,ymal对象写法,数组写法
yaml基本语法和yaml数据格式,ymal对象写法,数组写法
|
Python
apply函数的用法
apply是pandas处理数据经常用到的函数。我们可以用DataFrame的apply函数实现对多列、多行的操作。可通过axis设置参数,设为1是对列进行操作,参数axis设为0是对行操作。apply经常跟lambda一起使用,非常方便,大大提高了效率。
149 0
|
11月前
|
存储 Kubernetes Perl
k8s(10)声明式对象配置--yaml文件
k8s(10)声明式对象配置--yaml文件
85 0
|
传感器 编解码 数据可视化
costmap_common_params.yaml参数解析和修改要点
costmap_common_params.yaml参数解析和修改要点
1518 1
|
Serverless Perl
R|apply,tapply
R|apply,tapply