一、源码二、源码解析
1.remove_extent:移除数组的第一层维度2.remove_all_extents: 移除所有数组维度3.remove_pointer: 移除指针类型4.add_pointer : 添加指针类型5.is_array: 判断是否是数组类型6.is_reference:是否是引用类型。is_lvalue_reference: 左值引用,is_rvalue_reference: 右值引用7.is_pointer: 是否是指针类型8.is_null_pointer: 判断指针是否是空,利用is_same9.判断是否是基本类型(整形,浮点数,void,nullptr)10.is_union:判断是不是内联结构,is_class:判断是不是类对象。is_convertible:判断能否转化从from到to。is_enum:判断是不是枚举类型(只能看到定义。没有找到具体实现。待日后找到后补上)
一、源码老规矩先放源码
template二、源码解析 1.remove_extent:移除数组的第一层维度struct remove_extent { // remove array extent using type = _Ty; }; template struct remove_extent<_Ty[_Ix]> { using type = _Ty; }; template struct remove_extent<_Ty[]> { using type = _Ty; }; template using remove_extent_t = typename remove_extent<_Ty>::type; template struct remove_all_extents { // remove all array extents using type = _Ty; }; template struct remove_all_extents<_Ty[_Ix]> { using type = typename remove_all_extents<_Ty>::type; }; template struct remove_all_extents<_Ty[]> { using type = typename remove_all_extents<_Ty>::type; }; template using remove_all_extents_t = typename remove_all_extents<_Ty>::type; template struct remove_pointer { using type = _Ty; }; template struct remove_pointer<_Ty*> { using type = _Ty; }; template struct remove_pointer<_Ty* const> { using type = _Ty; }; template struct remove_pointer<_Ty* volatile> { using type = _Ty; }; template struct remove_pointer<_Ty* const volatile> { using type = _Ty; }; template using remove_pointer_t = typename remove_pointer<_Ty>::type; template struct _Add_pointer { // add pointer (pointer type cannot be formed) using type = _Ty; }; template struct _Add_pointer<_Ty, void_t *>> { // (pointer type can be formed) using type = remove_reference_t<_Ty>*; }; template struct add_pointer { using type = typename _Add_pointer<_Ty>::type; }; template using add_pointer_t = typename _Add_pointer<_Ty>::type; template _INLINE_VAR constexpr bool is_array_v = false; // determine whether type argument is an array template _INLINE_VAR constexpr bool is_array_v<_Ty[_Nx]> = true; template _INLINE_VAR constexpr bool is_array_v<_Ty[]> = true; template struct is_array : bool_constant > {}; #if _HAS_CXX20 template inline constexpr bool is_bounded_array_v = false; template inline constexpr bool is_bounded_array_v<_Ty[_Nx]> = true; template struct is_bounded_array : bool_constant > {}; template inline constexpr bool is_unbounded_array_v = false; template inline constexpr bool is_unbounded_array_v<_Ty[]> = true; template struct is_unbounded_array : bool_constant > {}; #endif // _HAS_CXX20 template _INLINE_VAR constexpr bool is_lvalue_reference_v = false; // determine whether type argument is an lvalue reference template _INLINE_VAR constexpr bool is_lvalue_reference_v<_Ty&> = true; template struct is_lvalue_reference : bool_constant > {}; template _INLINE_VAR constexpr bool is_rvalue_reference_v = false; // determine whether type argument is an rvalue reference template _INLINE_VAR constexpr bool is_rvalue_reference_v<_Ty&&> = true; template struct is_rvalue_reference : bool_constant > {}; template _INLINE_VAR constexpr bool is_reference_v = false; // determine whether type argument is a reference template _INLINE_VAR constexpr bool is_reference_v<_Ty&> = true; template _INLINE_VAR constexpr bool is_reference_v<_Ty&&> = true; template struct is_reference : bool_constant > {}; template _INLINE_VAR constexpr bool is_pointer_v = false; // determine whether _Ty is a pointer template _INLINE_VAR constexpr bool is_pointer_v<_Ty*> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* const> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* volatile> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* const volatile> = true; template struct is_pointer : bool_constant > {}; template _INLINE_VAR constexpr bool is_null_pointer_v = is_same_v , nullptr_t>; // determine whether _Ty is cv-qualified nullptr_t template struct is_null_pointer : bool_constant > {}; template struct is_union : bool_constant<__is_union(_Ty)> {}; // determine whether _Ty is a union template _INLINE_VAR constexpr bool is_union_v = __is_union(_Ty); template struct is_class : bool_constant<__is_class(_Ty)> {}; // determine whether _Ty is a class template _INLINE_VAR constexpr bool is_class_v = __is_class(_Ty); template _INLINE_VAR constexpr bool is_fundamental_v = is_arithmetic_v<_Ty> || is_void_v<_Ty> || is_null_pointer_v<_Ty>; template struct is_fundamental : bool_constant > {}; // determine whether _Ty is a fundamental type template struct is_convertible : bool_constant<__is_convertible_to(_From, _To)> { // determine whether _From is convertible to _To }; template _INLINE_VAR constexpr bool is_convertible_v = __is_convertible_to(_From, _To); template struct is_enum : bool_constant<__is_enum(_Ty)> {}; // determine whether _Ty is an enumerated type template _INLINE_VAR constexpr bool is_enum_v = __is_enum(_Ty);
例如remove_extent
//定义基础类型 templatestruct remove_extent { // remove array extent using type = _Ty; }; //对上述特化,利用模板特化反向推导出Ix的大小,并且移除掉[Ix]。 //例如传入的是int[10][2]最后剩下的类型也就是_Ty的类型是int[2] //特化擦除会将已有的擦除掉,因为[Ix]也就是[10]已经被定义了,剩下的_Ty = int[2] template struct remove_extent<_Ty[_Ix]> { using type = _Ty; }; //当传入的是没有指定大小的数组例如int[],这类的 template struct remove_extent<_Ty[]> { using type = _Ty; }; //重新定义类型。注意typename显示声明一个类型时使用 template using remove_extent_t = typename remove_extent<_Ty>::type;
测试demo
#includeusing namespace std; template struct MyStruct { using type = T; }; template struct MyStruct { constexpr static size_t value = Ix; using type = T; }; template struct MyStruct { using type = T; }; int main() { MyStruct ::type a; MyStruct ::type b; MyStruct ::type c; MyStruct ::type d; auto e = MyStruct ::value; MyStruct ::type f; return 0; }
我还是喜欢根据现象反推导实际的实现。根据定义看现象,容易陷入误区,还是实践靠谱。
根据demo测试尝试推测模板类型推导:实际就是有啥擦除啥,你自己特化了什么他就把那部分去除掉,感觉编译器实现的方式就是字符串匹配。找到最合适那个匹配到,已有的去除掉。就像int【10】【2】最后被提取了【10】,其实我以为会是【2】被提取走,剩下int【10】,但实际是先匹配的第一层。直接看结果比看啥定义靠谱。
2.remove_all_extents: 移除所有数组维度实际就是递归调用,直到所有数组都被擦除,然后返回最后的类型。
typename remove_all_extents<_Ty>::type
就是递归调用
type=
template3.remove_pointer: 移除指针类型struct remove_all_extents { // remove all array extents using type = _Ty; }; template struct remove_all_extents<_Ty[_Ix]> { //和上述这里不一致。 //这里递归调用自身,将全部数组擦除 using type = typename remove_all_extents<_Ty>::type; }; template struct remove_all_extents<_Ty[]> { //和上述这里不一致。 //这里递归调用自身,将全部数组擦除 using type = typename remove_all_extents<_Ty>::type; }; //重新定义类型。注意typename显示声明一个类型时使用 template using remove_all_extents_t = typename remove_all_extents<_Ty>::type;
//这对大家来说看的实在太多了。就是利用特化移除掉某个属性。这类的基本实现都一样。 template4.add_pointer : 添加指针类型struct remove_pointer { using type = _Ty; }; //特化,擦除掉指针类型 template struct remove_pointer<_Ty*> { using type = _Ty; }; //特化,擦除掉const指针类型 template struct remove_pointer<_Ty* const> { using type = _Ty; }; //特化,擦除掉volatile指针类型 template struct remove_pointer<_Ty* volatile> { using type = _Ty; }; //特化,擦除掉const volatile指针类型 template struct remove_pointer<_Ty* const volatile> { using type = _Ty; }; //新定义一个类型,方便使用 template using remove_pointer_t = typename remove_pointer<_Ty>::type;
与之前说过的添加引用类型类似
//普通模板+第二个参数是void因为特化要单参数使用void_t template5.is_array: 判断是否是数组类型struct _Add_pointer { // add pointer (pointer type cannot be formed) using type = _Ty; }; //remove_reference_t移除引用类型,之前讲过,就如上述实现方式一直,利用特化 擦除掉引用 //void_t *>擦除掉引用,后判断该类型能否定义为指针类型。不能则调用失败。 template struct _Add_pointer<_Ty, void_t *>> { // (pointer type can be formed) using type = remove_reference_t<_Ty>*; }; //中转战一样,又定义了一次。应该是为了隐藏实现。便于查看 template struct add_pointer { using type = typename _Add_pointer<_Ty>::type; }; //_t类型,统一格式利于使用。 template using add_pointer_t = typename _Add_pointer<_Ty>::type;
和之前数组类型擦除类似,不过那个是直接擦除重定义一个类型,这个是判断,特化的变量
//普通模板,也就是最后的出口。当所有特化都不满足才会被匹配到 template6.is_reference:是否是引用类型。is_lvalue_reference: 左值引用,is_rvalue_reference: 右值引用_INLINE_VAR constexpr bool is_array_v = false; // determine whether type argument is an array //是数组类型则能跟此特化匹配到,最后结果为true; template _INLINE_VAR constexpr bool is_array_v<_Ty[_Nx]> = true; //是数组类型则能跟此特化匹配到,最后结果为true; template _INLINE_VAR constexpr bool is_array_v<_Ty[]> = true; //定义一个bool_constant类型,判断是否是数组,最后会是true_type, false_type template struct is_array : bool_constant > {}; //就是将是否指定了大小分离开了,分成两个进行判断了 #if _HAS_CXX20 template inline constexpr bool is_bounded_array_v = false; //指定了大小 template inline constexpr bool is_bounded_array_v<_Ty[_Nx]> = true; template struct is_bounded_array : bool_constant > {}; template inline constexpr bool is_unbounded_array_v = false; //没有指定了大小 template inline constexpr bool is_unbounded_array_v<_Ty[]> = true; template struct is_unbounded_array : bool_constant > {}; #endif // _HAS_CXX20
这个实现看的太多了,都是利用特化进行判断类型。
template7.is_pointer: 是否是指针类型_INLINE_VAR constexpr bool is_lvalue_reference_v = false; // determine whether type argument is an lvalue reference template _INLINE_VAR constexpr bool is_lvalue_reference_v<_Ty&> = true; template struct is_lvalue_reference : bool_constant > {}; template _INLINE_VAR constexpr bool is_rvalue_reference_v = false; // determine whether type argument is an rvalue reference template _INLINE_VAR constexpr bool is_rvalue_reference_v<_Ty&&> = true; template struct is_rvalue_reference : bool_constant > {}; template _INLINE_VAR constexpr bool is_reference_v = false; // determine whether type argument is a reference template _INLINE_VAR constexpr bool is_reference_v<_Ty&> = true; template _INLINE_VAR constexpr bool is_reference_v<_Ty&&> = true; template struct is_reference : bool_constant > {};
都是利用特化变量,判断是否是指针类型。is开头的实现都差不多。
template_INLINE_VAR constexpr bool is_pointer_v = false; // determine whether _Ty is a pointer template _INLINE_VAR constexpr bool is_pointer_v<_Ty*> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* const> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* volatile> = true; template _INLINE_VAR constexpr bool is_pointer_v<_Ty* const volatile> = true; template struct is_pointer : bool_constant > {};
需要注意为很么需要单独_Ty* const,因为又函数是const的,而模板匹配const int * 和int * const显然不是同一个概念。
demo
#include8.is_null_pointer: 判断指针是否是空,利用is_sameusing namespace std; template constexpr bool is_pointers = false; // determine whether _Ty is a pointer template constexpr bool is_pointers<_Ty*> = true; int main() { auto a = is_pointers ; auto b = is_pointers ; return 0; }
template9.判断是否是基本类型(整形,浮点数,void,nullptr)_INLINE_VAR constexpr bool is_null_pointer_v = is_same_v , nullptr_t>; // determine whether _Ty is cv-qualified nullptr_t //remove_cv_t<_Ty>移除掉const,volatile属性 //利用is_same判断remove_cv_t<_Ty和nullptr_t是不是一个类型,是则为ture,不是则为false. template struct is_null_pointer : bool_constant > {}; //继承bool_constant最后为true_type, false_type;
template10.is_union:判断是不是内联结构,is_class:判断是不是类对象。is_convertible:判断能否转化从from到to。is_enum:判断是不是枚举类型(只能看到定义。没有找到具体实现。待日后找到后补上)_INLINE_VAR constexpr bool is_fundamental_v = is_arithmetic_v<_Ty> || is_void_v<_Ty> || is_null_pointer_v<_Ty>; //is_arithmetic_v判断是不是算数类型,利用模板继承+is_same可变参数,一次提取比较, //is_void_v判断是不是void类型 //is_null_pointer_v判断是不是空指针。 //is_arithmetic_v, is_void_v具体见其他文章。有介绍。 template struct is_fundamental : bool_constant > {}; // determine whether _Ty is a fundamental type
templatestruct is_union : bool_constant<__is_union(_Ty)> {}; // determine whether _Ty is a union template _INLINE_VAR constexpr bool is_union_v = __is_union(_Ty); template struct is_class : bool_constant<__is_class(_Ty)> {}; // determine whether _Ty is a class template _INLINE_VAR constexpr bool is_class_v = __is_class(_Ty); emplate struct is_convertible : bool_constant<__is_convertible_to(_From, _To)> { // determine whether _From is convertible to _To }; template _INLINE_VAR constexpr bool is_convertible_v = __is_convertible_to(_From, _To); template struct is_enum : bool_constant<__is_enum(_Ty)> {}; // determine whether _Ty is an enumerated type template _INLINE_VAR constexpr bool is_enum_v = __is_enum(_Ty);



