03.模板元编程与函数式

文章介绍了C++中的模板函数特化、编译器优化,如使用模板参数实现编译期常量优化,以及模板参数在判断语句中的应用。还讨论了auto、decltype(auto)的自动类型推导,以及inline关键字和常引用的作用。另外,文章提到了右值引用、lambda表达式在函数式编程和异步编程中的使用,以及tuple和结构化绑定在处理多返回值和数据解包中的应用。
摘要由CSDN通过智能技术生成

模板函数-特化的重载;

如果函数无参,编译器无法推断,此时应:

add<int>();//手动给定模板参数类型

模板参数用于编译器优化:

1.整型可以作为模板参数

template<int N>
void show_times(std::string msg){
    for(int i=0;i<N;i++){
        std::cout<<msg<<std::endl;
    }
}


int main(){
    show_times<2>("two");
}

为什么要这么做?

优点:

         此时传入的N会作为编译期常量,对每个不同的N,编译器会单独生成代码,进而进行优化。

        而仅仅作为函数参数传入时,N是运行期常量,编译器无法自动优化。

缺点:

        编译器会根据N的不同生成很多份代码--二进制文件大小剧增,编译变慢。

2.模板参数用于判断语句:

将判断语句参数改成模板参数。在编译时会生成两份代码,对于不执行的情况会直接优化掉。防止了运行时开销。

template<bool debug>
int sum(int n){
    int res=0;
    if(debug){
        ...
    }

int main(){
    sum<true>(3);
    sum<false>(2);
    ...
}

自动类型推导auto

注意:无法用于类变量

inline关键字已经没用了,现在是由编译器来决定释放内联;

常引用不仅更加安全,且编译器也能大胆放心去优化。

右值:

不长时间存在于内存中的值,例如一些常值表达式;

此外,C++规定int&&能自动转化为const int&;


自动类型推导:万能推导(decltype(auto))

decltype与auto的区别:

1.auto类型说明符用编译器计算变量的初始值来推断其类型,而decltype虽然也让编译器分析表达式并得到它的类型,但是不实际计算表达式的值。

2.编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。

3.与auto不同,decltype的结果类型与表达式形式密切相关,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同。
 

代理模式中,用于完美转发函数的返回值:

#include<iostream>
#include<vector>
using namespace std;


template<class T1,class T2>
auto add(const std::vector<T1>&a,const std::vector<T2>&b){
    using T0=decltype(T1{}+T2{});//创建T1类型和T2类型的0值对象,用于类型推导;
    std::vector<T0>ret;
    for(size_t i=0;i<std::min(a.size(),b.size());i++){
        ret.push_back(a[i]+b[i]);
    }
    return ret;
}

int main(){
    
    std::vector<int>a={2,3,4};
    std::vector<float>b={0.5f,1.0f,2.0f};
    auto c=add(a,b);
    for(const auto&i:c)
        std::cout<<i<<endl;
    return 0;
}

using 创建类型别名,和typedef等价


函数式编程

函数也可作为另一个函数的参数,实际传参就是函数指针

template<class T>
void call_Fun(T fun){
    fun(0);
    fun(1);
}

int main(){

    call_Fun((auto n){return n*n;});//Lambad参数为auto就可以等价于模板函数;
    
}

异步编程

匿名递归

总结:

lambda作为参数:用template<classFunc>然后Funcconst&做类型。
lambda作为返回值:用auto做类型。
牺牲性能但存储方便:std::function容器。
lambda作为参数:通常用[&]存储引用。
lambda作为返回值:总是用[=]存储值。


tuple

int main(){
    
    auto tup=std::tuple<int,float,char>{3,3.14f,'h'};
    auto first=std::get<0>(tup);//可以使用std::get来解包;
    auto second=std::get<1>(tup);
    auto third=std::get<2>(tup);
    

    //也可以使用结构化绑定语法;
    auto[x,y,z]=tup;
    std::cout<<x<<endl;
    std::cout<<y<<endl;
    std::cout<<z<<endl;
}

结构化绑定也可以用于自定义类//C++ 17

class Test{
public:
    Test(int _x,string _s):n(_x),s(_s){};
    void add(int i,int j){
        std::cout<<i+j<<endl;
    }
    int n;
    string s;
};

int main(){

    Test t(1,"hello world!");
    auto [x,y]=t;
    std::cout<<x;
}

tuple的另一个用法是返回多个返回值!
 

课程链接:【公开课】现代C++进阶:模板元编程与函数式_哔哩哔哩_bilibili

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值