#ifndef _STATIC_H_ #define _STATIC_H_ //静态反射库(C++26提案中出现C++静态反射) //但是C++能通过一些现有的手段实现静态反射,这里尝试一下写一个C++的静态反射 //验证宏的参数个数 //这个也很有意思,用了64个占位符号, #define EMPTY_MACRO_CHECK(...) __VA_ARGS__ EMPTY_MACRO_CHECK_1 //用于实现判断参数个数是不是零个,如果是0个将返回一个全空的字符串 #define EMPTY_MACRO_CHECK_1(...) #__VA_ARGS__ #define GET_NTR_AGR( \ _1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18, \ _19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,\ _31,_32,_33,_34,_35,_36,_37,_38,_39,\ _40,_41,_42,_43,_44,_45,_46,_47,_48,_49,\ _50,_51,_52,_53,_54,_55,_56,_57,_58,_59, \ _60,_61,_62,_63,_64,n,...)n #define GET_ARG_COUNT(...) GET_NTR_AGR(__VA_ARGS__, \ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,0 ) \ //接下来一个计算结构体的参数类型的泛型 struct Any_type { template operator T(); //即代表在模板中Any_type结构体可以转换为任意类型(当然,这个只能在编译期的模板中使用) //这是C++模板的一个很重要的特性,即C++在模板中不会关注这个类型能否这样进行转换,也不关注是怎么进行转换的 //(这也是为什么这个函数连函数体都可以没有) //C++模板推导过程中只关注这个函数的转换的类型结果是什么 //同时也可以引出另一个特性,即C++模板推导中使用一个函数的返回值作为推导依据时,同样C++也只关注返回值类型是什么 //同时C++的特化是做惰性特化,在运行期不调用的函数根本不会进行特化 //这也就是为什么这个函数可以存在且运行期不会报错的原因,因为C++根本没有生成这个模板函数的实例 //下面就是一个例子 }; /****************************************** * 加上第二个前置的知识SFINAE(Substitution failure is not an error) * 首先一言以蔽之,这实际上可以理解为模板的重载 * 这几个词确实很抽象 * 一个一个解释Substitution指的是模板匹配的过程 * failure失败,歧义主要出现在这里 * 在计算机程序中的失败和现实中不太一样 * 看一个例子(if语句) *int a=0; *if(a==1) * a++; *if(a==0) * a--; * 首先在if(a==1)中会匹配失败(failure) * 但是会继续去匹配if(a==0)即failure is not error * * * ******************************************/ // template // consteval int CountMember(Args&&... args) 等价写法 template consteval int CountMember(auto&&... Args) { if constexpr(!requires{T{Args...};}) { return sizeof...(Args)-1; } else{ return CountMember(Args... , Any_type{}); //递归添加一个额外的参数 } } #endif