C++ 模板元编程简单小栗子

最近看了看模板的元编程,感觉有点意思。

一些计算可以在编译过程就能够完成,榨干编译器的最后一点资源。

stl中用的全是这些玩意。

当然,这增加了编译时长。

 

我记得貌似有“图灵完备”这个说法——模板的元编程现在能够实现判断跳转、循环,理论上来说,一般能够用运行时解决的问题,在编译时都能够解决。

但这个好像没有什么意义。如果通篇都用这种代码来编写程序,那么这和直接嵌入汇编有什么区别?

我学这个纯属是为了让别人看不懂。

(我真的猜不透你耶……)

疯子就应该有疯子应该有的疯度。

 

写了几个小例子用来备忘。

学习参考链接: https://www.cnblogs.com/qicosmos/p/4480460.html

 

1.判断类型是否相同(C++自带也有 std::is_same<T1, T2>::value)

 1 template <typename T1, typename T2>    
 2 struct is_same_type
 3 {
 4     enum { value = false };
 5 };
 6 
 7 template <typename T>
 8 struct is_same_type<T, T>    
 9 {
10     enum { value = true };
11 };

 

 

2.计算阶乘

 1 //n!
 2 template<int n>
 3 struct factorial
 4 {
 5 private:
 6     enum: unsigned long long {
 7         tmp = n * factorial<n - 1>::value  //It is useless.
 8     };
 9 
10 public:
11     enum {
12         value = tmp >= INT_MAX ? -1 : tmp    //return n * factorial(n - 1);
13     };        
14 };
15 
16 template<>
17 struct factorial<0>    //if(0 == n)
18 {
19     enum { value = 1 };    //return 1
20 };

 

 

3.获取一组数中最大的数

 1 //get max number.
 2 template<int n, int... ns>
 3 struct max_num
 4 {
 5     enum {value = n};    //return n;
 6 };
 7 
 8 template <int ln/*left number*/, int rn/*right number*/, int... ns/*numbers...*/>
 9 struct max_num<ln, rn, ns...>
10 {
11     enum {value = 
12         ln >= rn ?        //if(ln >= rn)
13             max_num<ln, ns...>::value :        //max_num(ln)
14             max_num<rn, ns...>::value        // else  max_num(rn)
15     };
16 };

 

4.根据模板中不同的类型来获得不同的值(比如SocketTCP 和 SocketTCP  使用不同的协议类型和数据传输类型)

 1 enum PROTO_TYPE
 2 {
 3     PROTO_NONE = 0,
 4     PROTO1 = 1,
 5     PROTO2 = 2
 6 };
 7 
 8 class A
 9 {
10 };
11 
12 class B
13 {
14 };
15 
16 template <class T>
17 struct getproto
18 {
19     enum {
20         value =        //value = 
21             std::is_same<T, A>::value ? PROTO1 :        //if(typeT == typeA) return PROTO1;
22             std::is_same<T, B>::value ? PROTO2 :        //else if(typeT == typeB) return PROTO2;
23             //TODO: others...
24         PROTO_NONE        //else return PROTO_NONE;
25     };
26 };



 

5. 编译时循环

前面的阶乘计算和寻找最大的数都用到了循环,本质是递归。他们类似于这样

 1 template<int b_, int e_>
 2 struct LOOP_CALL
 3 {
 4     LOOP_CALL()
 5     {
 6         LOOP_CALL<b_, e_ - 1>();
 7         // TODO: loop once, index is e_ - 1
 8         //
 9     }
10 };
11 
12 template<int b_>
13 struct LOOP_CALL<b_, b_>
14 {
15     LOOP_CALL(){ }
16 };

  其中, 循环范围是 [b_, e_)。

  但这里也存在着问题。由于它的本质是递归,那么编译器定会对这种递归的层数有上限设定。比如我在main函数中调用  LOOP_CALL<0, 1000>();  ,此时编译器报错(使用 mingw32-make 进行编译):

[build] C:\Users\user-20220927-001\Desktop\tt\cpp\test.h: In instantiation of 'LOOP_CALL<b_, e_>::LOOP_CALL() [with int b_ = 0; int e_ = 101]':
[build] C:\Users\user-20220927-001\Desktop\tt\cpp\test.h:88:9:   recursively required from 'LOOP_CALL<b_, e_>::LOOP_CALL() [with int b_ = 0; int e_ = 999]'
[build] C:\Users\user-20220927-001\Desktop\tt\cpp\test.h:88:9:   required from 'LOOP_CALL<b_, e_>::LOOP_CALL() [with int b_ = 0; int e_ = 1000]'
[build] C:\Users\user-20220927-001\Desktop\tt\cpp\main.cpp:8:24:   required from here
[build] C:\Users\user-20220927-001\Desktop\tt\cpp\test.h:88:9: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
[build]          LOOP_CALL<b_, e_ - 1>();
[build]          ^~~~~~~~~~~~~~~~~~~~~~~
[build] compilation terminated.

  当递归层数到达900时,编译器就开始报错了,并提示用 -ftemplate-depth= 来更改设置。但如果不更改设置的情况下,如何解决这个问题?

  我所想到的办法就是:既然不允许一次递归层数太多,那么我可以每一个调用递归100次,执行10次调用,就可以做到  LOOP_CALL<0, 1000>();  的成功执行,类似于:

1 #define __Partition (100)
2 
3 LOOP_CALL<0, __Partition>();
4 LOOP_CALL<__Partition, __Partition * 2>();
5 LOOP_CALL<__Partition * 2, __Partition * 3>();
6 //......

  这部分依然可以用递归去解决:

 1 #define __Min            (1)
 2 #define __Max           (1000)
 3 #define __Partition     (100)
 4 
 5 #define __IsNotNeedSplit (__Max - __Min <= __Partition)
 6 
 7 template<int b_, int e_, bool is_>
 8 struct __RecursivePartition
 9 {
10 };
11 
12 template<int b_, int e_>
13 struct __RecursivePartition<b_, e_, true>
14 {
15     __RecursivePartition()
16     {
17         LOOP_CALL<b_, e_>();
18     }
19 };
20 
21 template<int b_, int e_>
22 struct __RecursivePartition<b_, e_, false>
23 {
24     enum 
25     {
26         next_b = b_ + __Partition,
27         is_ = (e_ - next_b <= __Partition),
28     };
29 
30     __RecursivePartition()
31     {
32         LOOP_CALL<b_, b_ + __Partition>();
33         __RecursivePartition<next_b, e_, is_>();
34     }
35 };

  然后在调用时:

__RecursivePartition<__Min, __Max, __IsNotNeedSplit>();

  这样一个语句就可以了。

 

0.主函数用来测试

 1 int main()
 2 {
 3     std::cout << "is_same_type: " <<is_same_type<int, int>::value << std::endl;
 4     std::cout << "factorial:" << factorial<10>::value << std::endl;
 5     std::cout << "max_num:"<< max_num<1, 2, 54, 2, 36, 4>::value << std::endl;
 6 
 7     std::cout << "getproto: " << getproto<B>::value << std::endl;
 8 
 9     system("pause>nul");
10     return 0;
11 }

 

posted on 2019-05-08 15:10  __Even  阅读(375)  评论(0编辑  收藏  举报

导航