type_traits--3

一、源码

老规矩先放源码

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);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值