现代C++之模板元编程(今天写个If与While)

2020-02-13 11:45:27 浏览数 (1)

现代C 之模板元编程(今天写个If与While)

0.导语

今天就放轻松,有可能代码写的看的很晦涩,自己多敲几遍即可,下面来进入正文,如何使用模板元编程实现IF与WHILE。

1.IF实现

我们想要的目标如下:

代码语言:javascript复制
// 加减
template<bool cond, int nums1, int nums2>
struct addSub {
    static const auto RES = IF<cond, Add_<nums1, nums2>, Sub_<nums1, nums2>>::result::value;
};
// 调用
cout << addSub<true, 10, 2>::RES << endl;

当IF条件成立就将两数相加,否则两数相减,就是IF...Then...Else...的逻辑。

首先声明一个空的结构体:

代码语言:javascript复制
template<bool cond,
        typename Then,
        typename Else>
struct IF;

我们想一下,当IF中的cond条件成立,是不是输出结果就是Then,否则结果就是Else,因此我们只需要获取这两个即可呗。

因此,引出两个偏特化版本:

  • 条件成立
代码语言:javascript复制
template<typename Then,
        typename Else>
struct IF<true, Then, Else> {
    typedef Then result;
};
  • 条件失败
代码语言:javascript复制
template<typename Then,
        typename Else>
struct IF<false, Then, Else> {
    typedef Else result;
};

这个搞定了,现在就简单了,编写Then是什么,Else是什么不就得了,因此又得到:

代码语言:javascript复制
template<int nums1, int nums2>
struct Add_ {
    static const int value = nums1   nums2;
};

template<int nums1, int nums2>
struct Sub_ {
    static const int value = nums1 - nums2;
};

最后我们一封装,就是下面这个:

代码语言:javascript复制
template<bool cond, int nums1, int nums2>
struct addSub {
    static const auto RES = IF<cond, Add_<nums1, nums2>, Sub_<nums1, nums2>>::result::value;
};

然后一调用:

代码语言:javascript复制
addSub<true, 10, 2>::RES

我们的模板实现IF就完成了,哈哈~

除此之外,也可以编写其他需求:

例如:判断输入的数的奇偶性。

代码语言:javascript复制
// 判断奇数与偶数
template<int N>
struct isEven {
    static const auto RES = IF<N & 1 == 0, true_type, false_type>::result::value;
};

调用:

代码语言:javascript复制
cout << isEven<10>::RES << endl;

2.WHILE实现

有了IF,WHILE就水到渠成。

原理是一毛一样!

例如:求0~n的和。

代码语言:javascript复制
template<int n>
struct Sum {
    typedef SumLoop<0, n> type;
};
// 调用
cout << While<Sum<6>::type>::type::value << endl;

因此编写While就成了关键。里面的Sum是判断的条件。

故模仿IF编写,我们先声明一个WhileLoop:

代码语言:javascript复制
template<bool condition,
        typename Body>
struct WhileLoop;

紧接着,两个偏特化:

  • 条件成立
代码语言:javascript复制
template<typename Body>
struct WhileLoop<true, Body> {
    typedef typename WhileLoop<
            Body::cond_value,
            typename Body::next_type>::type
            type;
};

此处需要注意:针对while来说,条件成立后,是不断的循环,直到条件不满足,因此这里的true取Body的cond_value成员,而body取Body的next_type,在之后编写循环条件的时候,需要包含这两个。

  • 条件否定
代码语言:javascript复制
template<typename Body>
struct WhileLoop<false, Body> {
    typedef
    typename Body::res_type type;
};

直接把Body的res_type进行返回,便是最后的结果。

最后,编写循环所需的内容:

代码语言:javascript复制
template<int result, int n>
struct SumLoop {

    // 循环的条件
    static const bool cond_value =
            n != 0;

    // 循环后的结果
    static const int res_value =
            result;

    // 循环时的状态
    typedef my::integral_constant<
            int, res_value>
            res_type;

    // 循环执行一次时的状态
    typedef SumLoop<result   n, n - 1>
            next_type;
};

这里integral_constant可以是自己写的,也可以是std里面的。

代码语言:javascript复制
namespace my {
    template<class T, T v>
    struct integral_constant {
        static const T value = v;
        typedef T value_type;
        typedef integral_constant<T, v> type;
    };
}

integral_constant就是对模板参数进行了重新命名,非常简单。

然后,调用:

代码语言:javascript复制
cout << While<Sum<6>::type>::type::value << endl;

在C 14之后,有了下面语法,因此上述调用可以被简化:

代码语言:javascript复制
template<int n>
using Sum_t = SumLoop<0, n>;
// 调用
cout << While_t<Sum_t<6>>::type::value << endl;

0 人点赞