使用模板实现编译器IF判断和WHILE循环

用于记录对于template 编译器计算的学习

C++ 的模板处理和实现在编译期进行,理论上说 C++ 模板可以执行任何计算任务,但实际上因为模板是编译期计算, 其能力受到具体编译器实现的限制。

另外 if constexpr 条件判断也发生在编译期

编译器if else 选择

template<bool cond,
        typename Then,
        typename Else>
struct IF;//原始模板


template<typename Then,
        typename Else>
struct IF<true, Then, Else> {
    typedef Then result;
};//偏特化模板,用于处理状态cond为true的情况的分支

template<typename Then,
        typename Else>
struct IF<false, Then, Else> {
    typedef Else result;
};//偏特化模板,用于处理状态cond为false的情况的分支 
//Then和Else 通常是std::true,std::false或者其他处理模板

 通过使用对于模板的偏特化,实现在编译器进行IF ELSE 的分支选择。

template实现编译期递归

template<int n>
struct factorial {
    static_assert(n >= 0, "Arg must be non-negative");
    //报错,正常的执行不会在该模板中执行到n==0的情况
    static const int value = n * factorial<n - 1>::value;
};

template<>
struct factorial<0> {
    static const int value = 1;
};//n==0的特例化情况

使用template实现fmap(一个函数对于一组参数进行处理)

template<    //一个定义两个类型的模板,默认的OutContainer是vector,传入的模板为vector
        template<typename, typename>
        class OutContainer = vector,
        typename F, class R>    // 函数F和类型R
auto fmap(F &&f, R &&inputs) {
// 因为 F 和 R 均是模板type 因此 F&& 和 R&& 在此处均是万能引用
    typedef decay_t<decltype(f(*inputs.begin()))> result_type; //decay_t 使类型退化为原始类型
    
    OutContainer<result_type, allocator<result_type >> result;
    //创建存储result_type的容器
    for (auto &&item:inputs) {
        result.push_back(f(item));
    }
    return result;//批量计算函数,使一个函数能够对一系列数据进行运算
}

int add_1(int x) {
    return x + 1;
}

int main() {
    vector<int> v{1, 2, 3, 4, 5};
    auto result = fmap(add_1, v);
}

值得注意的是:

        std::decay_t的作用是使变量退化,变为其原始类型,如 int & ->int ,  double * -> double 
        向模板传入模板的时候可以像以上的形式,template<typename ,typename> class Outcontainer=vector,声明号模板的参数个数然后使用传入的模板进行赋值就可以(正如上述中vector模板传入的参数有两个,一个为类型type、一个为容器分配器Allocator<type> )
        

综合上述的一些模板编译器计算处理的技巧,可以使用模板实现编译器While循环来进行计算:

利用template实现编译期While循环
 

//typename 后面的有:: 符号,且后面参数是一个类型 用于说明后面跟随的是一个type

template<bool conditon,typename Body>
struct WhileLoop;

template<typename Body>
struct WhileLoop<true, Body> {
    typedef typename WhileLoop< Body::cond_value,typename Body::next_type>::type type;
};

template<typename Body>
struct WhileLoop<false, Body> {
    typedef typename Body::res_type type;
};
//以上三个WhileLoop为递归运算,用于对Body中的res_type进行递归求值

template<typename Body>
struct While {
    typedef typename WhileLoop< Body::cond_value, Body>::type type;
};

template<typename Body>
using While_t = WhileLoop< Body::cond_value, Body>; // While_t 是WhileLoop 的别名
//While的作用是 调用 实例化Whileloop 形成循环 

namespace my {
    template<typename T,T v>
    struct integral_constant {
        static const T value = v;               //值
        typedef T value_type;                   //类型名
        typedef integral_constant<T, v> type;   //自身
    };
};// Body的res_type的存储结构,因为是使用 type 的形式进行递归运算,所以应当使用 类模板来进行存储

template<int result,int n>
struct SumLoop {
    static const int result_value = result;//当前的值 const是为了在编译期就有值
    static const bool cond_value = n !=0;//结束条件
    typedef  my::integral_constant<int, result_value> res_type;//当前循环的状态
    typedef  SumLoop<result + n, n - 1> next_type;//下一次循环
};
//SumLoop 是循环主体 Body

template<int n>
struct Sum {
    typedef  SumLoop<0, n> type;//Sum::type是SumLoop<0,n>的别名
};

template<int n>
using Sum_t = SumLoop<0, n>; //Sum_t是SumLoop<0,n>的别名
// Sum和Sum_t 是SumLoop 的抽象封装
int main(){
    cout <<  While< Sum<6>::type >::type::value<<endl;
    cout <<  While< SumLoop <0, 6> >::type::value << endl;
    cout <<  WhileLoop<SumLoop <0, 6>::cond_value, SumLoop <0, 6>>::type::value << endl;
    // 以上三种情况都是相同的模板运算,只是由抽象到具体
    //While是WhileLoop的封装,Sum是SumLoop的封装,实质为WhileLoop根据SumLoop的状态cond_value 
    //来逐步递归得到SumLoop的最后一次next_type的值result_type并重命名为type,最后取type中的value即可
    //因为最后得到的 type 是integral_constant的结构体

    cout << While_t< Sum_t<6> >::type::value << endl;
    // 使用using来代替typedef对于type来进行引用
}

 While循环的由内到外的层次
    my::itergral_constant ->  SumLoop -> Sum        -> WhileLoop             ->         While
                   单个数据      ->  循环体  -> 循环体封装 -> 递归获取res_type -> 递归封装

typename在typedef 中,且后面参数为 type(类型)参数,且为其他作用域中的成员时,才需要在其前面加typename 即 typedef  typename  A::B  C 这种形式 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值