现代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,因此我们只需要获取这两个即可呗。
因此,引出两个偏特化版本:
- 条件成立
template<typename Then,
typename Else>
struct IF<true, Then, Else> {
typedef Then result;
};
- 条件失败
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;
紧接着,两个偏特化:
- 条件成立
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,在之后编写循环条件的时候,需要包含这两个。
- 条件否定
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里面的。
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;