需求
考虑两个 10 进制非负整数的相加,如:199 + 1 = 200,35635368953573875834674647 + 3579847859469476976 = 35635372533421735304151623 。
由于该整数的长度可能超过c++基本类型的范围,因此需要通过数组的方式来存储,并计算相加的结果。
要求不运行代码即可得出结果。
思路
- 定义模板类Cont,表示数组,整数的每一位都是数组元素。
- 定义打印类print,其成员函数fun()可以依次打印数组的值。
- 定义翻转数组的类Reverse,可实现整数的翻转,即:低位在前,高位在后。
- 实现加法逻辑,考虑进位和不同长度的整数相加。
- 调用之前实现的数组翻转元函数,将结果数组翻转,确保高位位于数组的开头,低位位于数组的结尾。
- 调用之前实现的 print 函数,打印输出结果。
源代码
#include <iostream>
using namespace std;
// 定义数组
template <unsigned... t>
struct Cont;
// 打印编译器的数组
template <typename T>
struct print;
template <unsigned T1, unsigned... T>
struct print<Cont<T1, T...>>
{
inline static void fun()
{
cout << T1;
print<Cont<T...>>::fun();
}
};
template <>
struct print<Cont<>>
{
inline static void fun()
{
cout << endl;
}
};
// 翻转数组
template <typename... T>
struct Reverse;
template <unsigned... tP, unsigned t, unsigned... tR>
struct Reverse<Cont<tP...>, Cont<t, tR...>>
{
using type = typename Reverse<Cont<t, tP...>, Cont<tR...>>::type;
};
template <unsigned... tP>
struct Reverse<Cont<tP...>, Cont<>>
{
using type = Cont<tP...>;
};
// 数组按位相加
template <typename T1, typename T2, typename T3, typename T4>
struct Plus;
template <unsigned T, typename = void>
struct PlusExt;
template <unsigned T>
struct PlusExt<T, std::enable_if_t<(T < 10)>>
{
constexpr static unsigned give = 0;
constexpr static unsigned tmp = T;
};
template <unsigned T>
struct PlusExt<T, std::enable_if_t<(T >= 10)>>
{
constexpr static unsigned give = 1;
constexpr static unsigned tmp = T - 10;
};
template <unsigned t1, unsigned... tR1, unsigned t2, unsigned... tR2, unsigned carry, unsigned... res>
struct Plus<Cont<res...>, Cont<carry>, Cont<t1, tR1...>, Cont<t2, tR2...>>
{
constexpr static unsigned tmp = PlusExt<t1 + t2 + carry>::tmp;
constexpr static unsigned give = PlusExt<t1 + t2 + carry>::give;
using type = typename Plus<Cont<res..., tmp>, Cont<give>, Cont<tR1...>, Cont<tR2...>>::type;
};
// t1数组的长度大于t2数组
template <unsigned... res, unsigned carry, unsigned t, unsigned... tR>
struct Plus<Cont<res...>, Cont<carry>, Cont<t, tR...>, Cont<>>
{
constexpr static unsigned tmp = PlusExt<t + carry>::tmp;
constexpr static unsigned give = PlusExt<t + carry>::give;
using type = typename Plus<Cont<res..., tmp>, Cont<give>, Cont<tR...>, Cont<>>::type;
};
// t1数组的长度小于t2数组
template <unsigned... res, unsigned carry, unsigned t, unsigned... tR>
struct Plus<Cont<res...>, Cont<carry>, Cont<>, Cont<t, tR...>>
{
constexpr static unsigned tmp = PlusExt<t + carry>::tmp;
constexpr static unsigned give = PlusExt<t + carry>::give;
using type = typename Plus<Cont<res..., tmp>, Cont<give>, Cont<>, Cont<tR...>>::type;
};
template <typename T1, typename T2>
struct LastResult;
template <unsigned... result, unsigned Carbit>
struct Plus<Cont<result...>, Cont<Carbit>, Cont<>, Cont<>>
{
using type = typename LastResult<Cont<Carbit>, Cont<result...>>::result;
};
template <unsigned car_bit, unsigned... input>
struct LastResult<Cont<car_bit>, Cont<input...>>
{
using result = std::conditional_t<car_bit, Cont<car_bit, input...>, Cont<input...>>;
};
int main()
{
using a1 = Cont<1, 9, 9>;
using a2 = Cont<1>;
using a1R = Reverse<Cont<>, a1>::type;
using a2R = Reverse<Cont<>, a2>::type;
using a1Rplusa2R = Plus<Cont<>, Cont<0>, a1R, a2R>::type;
using a1Plusa2 = Reverse<Cont<>, a1Rplusa2R>::type;
print<a1Plusa2>::fun();
return 0;
}
结果展示
代码写好后软件自动提示结果(IDE为vscode),编译前就可显示出来。
总结
元编程是一种强大的编程技术,能在编译期就完成部分软件功能,从而达到提高软件执行效率、验证代码逻辑和数据规范等功能。
但元编程的编码方式比较特殊,需要花时间练习。
以上元编程代码中用到了以下技巧:
- 类模板
- 变长模板
- 类模板的特化和限制
- 元编程的分支和循环语句