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