• c++_learning-模板元编程


    元编程:

    将各种计算从运行期提前至编译期,以达到提升运行时性能的目的,即是通过增加程序编译时间,来提升程序运行效率的编程手法。元编程中会使用到“递归”技术。

    boost库中,MPL(meta-programming library)库,用于辅助模板元编程,《c++模板元编程》有详细介绍。

    元函数:

    定义:

    • 能在编译期间,被调用和执行的函数(编译期间就能得到结果)。

    • 所谓元编程,就是书写和利用这些元函数进行编程

    • 举例:c++11 引入的 constexpr 关键字(c++17中使constexpr自带inline属性):用于在编译时求值。

      #include 
      using namespace std;
      
      // 元函数(数值元函数):
      constexpr int func(int val)
      {
          return val * 2;	
      }
      
      int main()
      { 
          // 因func()函数和val变量前均加了constexpr关键字,故val在编译期间,就能进行计算
          constexpr int val = func(12);
          static_assert(val == 24, "std error");
          // static_assert:用于在编译时进行断言检查
      
          // 元函数运行期间,也能调用
          int x = 10;
          cout << func(x) << endl;
      
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

    数值元函数:

    编译期间,能够被调用的类模板:

    #include 
    using namespace std;
    
    /* 要求:实现编译期间,阶乘的计算 */
    // 泛化版本:
    template <int val>
    class Factorial 
    {
    public:
        enum
        {
            value = val * Factorial<val - 1>::value
        };
    };
    // 特化版本:用于递归结束的出口
    template <>
    class Factorial<1>
    {
    public:
        enum
        {
            value = 1
        };
    };
    
    int main()
    {
        cout << Factorial<5>::value << endl;
    
        return 0;
    }
    
    • 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

    constexpr修饰的函数:

    #include 
    using namespace std;
    
    /* 要求:函数内部递归,实现编译期间,阶乘的计算 */
    namespace _nmsp_recursive {
        constexpr int Factorial(int val)
        {
            return val <= 1 ? 1 : (Factorial(val - 1) * val);	
        } 
    }
    
    /* 要求:函数内部for循环,实现编译期间,阶乘的计算 */
    namespace _nmsp_for {
        constexpr int Factorial(int val)
        {
            int result = 1;
            for (; val > 0; --val)
            {
                result *= val;	
            }
            return result;
        }   
    } 
    
    int main()
    {
        constexpr int val = Factorial(5);
        static_assert(val == 120, "std error");
        cout << val << endl;
    
        return 0;
    }
    
    • 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

    constexpr修饰的变量模板:

    #include 
    using namespace std;
    
    /* 要求:实现编译期间,阶乘的计算 */
    namespace _nmsp_factorial {
    	// 泛化版本的变量模板
        template <int val>
        constexpr int result = val * result<val - 1>;
        // 特化版本的变量模板
        template <>
        constexpr int result<1> = 1;
    
        void test()
        {
            constexpr int val = result<5>;
            static_assert(val == 120, "std error");
            cout << val << endl; 
        }
    }
    
    
    /* 要求:实现编译期间,求和运算 */
    namespace _nmsp_sum {
        // 泛化版本的变量模板:只有参数为0个时,才会调用
        template <int... Args>
        constexpr int sum = 0;
    
        // 特化版本的变量模板
        template <int val, int... others>
        constexpr int sum<val, others...> = val + sum<others...>;
    
        void test()
        {
            constexpr int val = sum<1,2,3,4,5>;
            static_assert(val == 15, "std error");
            cout << val << endl; 
        }
    } 
    
    • 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

    类型元函数:

    std::remove_all_extents类模板,实现的元编程就是靠“递归模板实例化”来驱动的。

    • 用using来定义类型别名的类模板(fixed trait类模板),就可以成为类型元函数。
    #include 
    using namespace std;
     
    template <typename T>
    class AddPoint
    {
    public:
        using type = T*;
    }; 
    
    int main()
    {
        AddPoint<const char>::type str = "hello";
        cout << typeid(str).name() << endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • using定义的变量模板,也可称为类型元函数。
    #include 
    using namespace std;
     
    template <typename T>
    using AddPoint = T*;
    
    int main()
    {
        AddPoint<const char> str = "hello";
        cout << typeid(str).name() << endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    元函数总结:

    可宽泛的认为:只要用于元编程中,且编译器期间能够被调用,都可以视为元函数(不避局限于类型元函数、数值元函数)。

    混合元编程:

    定义:

    1. 写出一个段元编程的代码;
    2. 编译器根据这段代码编译(生成)一段新的代码,实际程序真正的功能就是这段新代码;
    3. 编译器会对这段新代码进行编译,产生出最终的可执行程序;

    混合元编程计算点积:

    “常规的计算点积”与“混合元编程计算点积”的对比:

    #include 
    using namespace std;
    
    /* 实现两个一维数组的点积运算:*/
    namespace _OrdinaryOperation
    {
        // 函数模板:
        template <typename T, size_t n>
        T DotProduct(const T* arr1, const T* arr2)
        {   
            T result = T{};  // 零初始化	
    
            for (int i = 0; i < n; ++i)
            {
                result += ((*(arr1++)) * (*(arr2++)));
            }
            return result;
        }
    }
    
    namespace _Mixed_MetaProgram
    {
        // 泛化版本:
        template <typename T, size_t n>
        class DotProduct
        {
        public:
            static T result(const T* arr1, const T* arr2)
            {
            	return (*arr1) * (*arr2) + DotProduct<T, n - 1>::result(arr1 + 1, arr2 + 1);
            }
        };
        // 特化版本:用于递归的出口
        template <typename T>
        class DotProduct<T, 0>
        {
        public:
            static T result(const T* arr1, const T* arr2)
            {
                return T{};  // 零初始化	
            }
        }; 
    }
    
    int main()
    {
        int arr1[3] = {1,2,3};
        int arr2[3] = {4,5,6};
    
        cout << _OrdinaryOperation::DotProduct<int, 3>(arr1, arr2) << endl;
    
        cout << _Mixed_MetaProgram::DotProduct<int, 3>::result(arr1, arr2) << endl;
        // 编译器会根据这行代码生成新的代码,如下:
        // cout << (*arr1) * (*arr2) + (*(arr1 + 1)) * (*(arr2 + 1)) + (*(arr1 + 2)) * (*(arr2 + 2)) << endl;
    
        return 0;
    }
    
    • 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

    注意:使用元编程计算点积时,当一维数组过长,编译器会智能的通过一些函数调用避免产生过分冗长的代码。但该过程会导致可执行程序的尺寸变大,即产生了代码膨胀

    c++编译的两个阶段:

    前期阶段:c++编译器直接对c++源码(元编程代码)进行解释执行,会产生一系列c++代码,故元编程才会被看作“c++代码生成器”

    后期阶段:针对前期产生的代码进行编译、链接,最终生成可执行文件。

    类模板实例化:

    #include 
    using namespace std;
    
    namespace _nmsp_1
    { 
        // 泛化版本:
        template <int x, int y>
        class InstantiationObserve
        {
        public:
        	static const int value = (x > y) ? InstantiationObserve<x - 1, y>::value : InstantiationObserve<x, x>::value;
        };
        // 特化版本:
        template <int x>
        class InstantiationObserve<x, x>
        {
        public:
            static const int value = x;
        };
    }
    
    namespace _nmsp_2
    { 
        // 泛化版本:
        template <int x, int y>
        class InstantiationObserve
        {
        public:
            using type = typename std::conditional<(x > y), InstantiationObserve<x - 1, y>, InstantiationObserve<x, x>>::type;
            static const int value = type::value;
        };
        // 特化版本:
        template <int x>
        class InstantiationObserve<x, x>
        {
        public:
            static const int value = x;
        };
    }
    
    int main()
    {
        // 元编程中,如果使用了条件运算符,则可能将所涉及到的类都实例化出来
        cout << _nmsp_1::InstantiationObserve<5,3>::value << endl; 
    
        // 元编程中,如果使用std::conditional,则可能避免将无用的类实例化出来
        cout << _nmsp_2::InstantiationObserve<5,3>::value << endl; 
        // 元编程中,如果使用了enum{}枚举类型,则可能代码在编译器进一步被简化
    
        return 0;
    }
    
    • 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

    元编程中“计算完整性”的概念:

    1. 状态变量:类模板中的模板参数;
    2. 迭代构造(循环构造):通过在类模板中融入递归编程技术来实现;
    3. 整数对象(整数运算):静态成员变量 或 枚举类型,其他功能类似于变量/常量。

    注意:

    1. 元编程中,不能使用变量,编译期能接受的只有静态变量
    2. 传统意义上的分支和循环在元编程中,只能通过条件运算符、特化、递归等手段实现。

    inline静态成员变量:

    • c++17开始,constexpr自带inline属性;

    • 使用枚举类型inline静态成员变量(c++11引入)相同,都不存在额外占用内存空间的问题 。

      #include 
      using namespace std;
      
      struct A
      {
          enum { value1 = 12 };
          static inline const int value2 = 12;
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    类型列表typelist实现:(类型计算范例)

    介绍:

    一个类型容器,对类型提供了一系列操作(将类型看作数据来操作)。本质:一个类模板,用来表示一个列表,其中存放的是一堆类型。

    自定义实现typelist类型列表:

    typelist的老式设计:列表头+嵌套列表

    #include 
    using namespace std;
    
    namespace _nmsp
    {
        /* ..... NullTypeList:表示空typelist列表 ..... */
        class NullTypeList {};
    
        /* ..... typelist类模板:实现列表头类型Head + Tail其余类类型 ..... */
        template <typename T, typename U = NullTypeList>
        class typelist
        {
        public:
            using Head = T;   
            using Tail = U;
        };
    	
        /* ..... is_empty类模板:判断typelist中类类型是否为空 ..... */
        // 泛化版本:
        template <typename TypeList>
        class is_empty
        {
        public:
            static const bool value = false;
        };
        // 特化版本:
        template <>
        class is_empty<NullTypeList>
        {
        public:
            static const bool value = true;
        };
    
        /* ..... size类模板:获取typelist中类类型的个数 ..... */
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename TypeList>
        class size;
        // 特化版本2:用来递归结束的出口
        template <>
        class size<NullTypeList>
        {
        public:
            static const size_t count = 0;
        };
        // 特化版本2:用来递归实例化展开
        template <typename T, typename U>
        class size<typelist<T, U>>
        {
        public:
            static const size_t count = size<U>::count + 1;
        };
    	
        /* ..... front类模板:获取typelist中,第一个类类型 ..... */
        template <typename TypeList>
        class front
        {
        public:
        	using type = typename TypeList::Head;
        };
    	
        /* ..... pop_front类模板:从typelist中,移除第一个类类型 ..... */
        template <typename TypeList>
        class pop_front
        {
        public:
        	using type = typename TypeList::Tail;
        };
    	
        /* ..... push_front类模板:给typelist头插一个类类型 ..... */
        template <typename TypeList, typename insertType>
        class push_front
        {
        public:
        	using type = typelist<insertType, TypeList>;
        };
    	
        /* ..... find类模板_1:在typelist中,根据索引查找类类型 ..... */
        /* 这种写法:容易出现越界问题,导致编译错误 */
        // 泛化版本:用作递归实例化
        template <typename TypeList, size_t index>
        class find_1 : public find_1<typename pop_front<TypeList>::type, index - 1>
        {}; 
        // 特化版本:作为递归结束的出口
        template <typename TypeList>
        class find_1<TypeList, 0> : public front<TypeList>
        {};  
    	
        /* ..... find类模板_2:在typelist中,根据索引查找类类型 ..... */
        /* 这种写法:容易出现越界问题,导致编译错误 */ 
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename TypeList, size_t index>
        class find_2;
        //特化版本1:递归结束的出口
        template <typename Head, typename Tail>
        class find_2<typelist<Head, Tail>, 0>
        {
        public:
        	using type = Head;
        };
        //特化版本:用于递归实例化的过程
        template <typename Head, typename Tail, size_t index>
        class find_2<typelist<Head, Tail>, index>
        {
        public:
        	using type = typename find_2<Tail, index - 1>::type;
        };
    	
        /* ..... find类模板_3:在typelist中,根据索引查找类类型 ..... */ 
        /* 这种写法:出现越界问题时,返回空列表即NullTypeList */
        // 泛化版本:当出现越界问题时,调用该泛化版本
        template <typename TypeList, size_t index, typename DefaultType = NullTypeList>
        class find_3
        {
        public:
        	using type = DefaultType;  
        };
        //特化版本1:递归结束的出口
        template <typename Head, typename Tail, typename DefaultType>
        class find_3<typelist<Head, Tail>, 0, DefaultType>
        {
        public:
        	using type = Head;
        };
        //特化版本:用于递归实例化的过程
        template <typename Head, typename Tail, size_t index, typename DefaultType>
        class find_3<typelist<Head, Tail>, index, DefaultType>
        {
        public:
        	using type = typename find_3<Tail, index - 1, DefaultType>::type;
        };
    }
    
    #define TypeList1(T1)              _nmsp::typelist<T1, _nmsp::NullTypeList>
    #define TypeList2(T1, T2)          _nmsp::typelist<T1, TypeList1(T2)>
    #define TypeList3(T1, T2, T3)      _nmsp::typelist<T1, TypeList2(T2, T3)>
    #define TypeList4(T1, T2, T3, T4)  _nmsp::typelist<T1, TypeList3(T2, T3, T4)>; 
    
    int main()
    {
        using typelist4 = TypeList4(int, bool, float, double);
        cout << _nmsp::is_empty<typelist4>::value << endl;
        cout << _nmsp::size<typelist4>::count << endl;
        cout << typeid(_nmsp::front<typelist4>::type).name() << endl;
        cout << "*************************************" << endl;
    
        using typelist3 = typename _nmsp::pop_front<typelist4>::type;
        cout << typeid(_nmsp::front<typelist3>::type).name() << endl;
        cout << _nmsp::size<typelist3>::count << endl;
        cout << "*************************************" << endl;
    
        using typelist4_ = typename _nmsp::push_front<typelist3, int>::type;
        cout << typeid(_nmsp::front<typelist4_>::type).name() << endl;
        cout << _nmsp::size<typelist4_>::count << endl;
        cout << "*************************************" << endl;
    
        cout << typeid(_nmsp::find_1<typelist4_, 2>::type).name() << endl;
        cout << typeid(_nmsp::find_2<typelist4_, 2>::type).name() << endl;
        cout << typeid(_nmsp::find_3<typelist4_, 4>::type).name() << endl;
    
        return 0;
    }
    
    • 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
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161

    typelist的新式设计:

    实现基本的操作接口:
    1. 判断typelist中类类型是否为空,即is_empty类模板;
    2. 获取typelist中类类型的个数,即size类模板;
    3. 提取typelist中的首个类类型,即front类模板;
    4. 从typelist中剔除第一个类类型,即pop_front类模板;
    5. 向typelist头插一个类类型,即push_front类模板;
    6. 向typelist尾插一个类类型,即push_back类模板;
    7. 替换typelist中首个类类型,即replace_front类模板;
    namespace _nmsp_baseInterface
    {
        /* ...... typelist类模板:用来接收一堆类类型 ...... */
        // 可变参模板参数,用来接收一堆类型,并存放在typelist中
        template <typename... T>
        class typelist;
    
        /* ...... is_empty类模板:判断typelist中类类型是否为空 ...... */
        // 泛化版本:typelist中类类型的个数不为0(即不为空)时,调用泛化版本
        template <typename TypeList>     // 此时,TypeList中存放了一堆类型
        class is_empty
        {
        public:
            static const bool value = false;
            //static inline const bool value = false;
            // 注意:inline variables are only available with ‘-std=c++17’ or ‘-std=gnu++17’
        };
        // 特化版本:typelist中类类型的个数为0(即为空)时,调用特化版本
        template <>
        class is_empty<typelist<>>
        {
        public:
            static const bool value = true;
        };
    
        /* ...... size类模板:获得typelist中类类型的个数 ...... */
        // 泛化版本:只声明,用来引出特化版本 
        template <typename TypeList>
        class size;
        // 特化版本:用来获取typelist中类类型的个数
        template <typename... TypeArgs>
        class size<typelist<TypeArgs...>>
        {
        public:
        	static const size_t count = sizeof...(TypeArgs);
        };
    
        /* ...... front类模板:提取typelist中的第一个类型 ...... */
        // 泛化版本:只声明,用来引出特化版本
        // 注意:只有TypeList中类类型为空时,才会调用泛化版本
        template <typename TypeList>
        class front;
        // 特化版本:用来提取出typelist中的第一个类型
        template <typename FirstType, typename... OtherTypes>
        class front<typelist<FirstType, OtherTypes...>>
        {
        public:
            using type = FirstType;
        };
    
        /* ...... pop_front类模板:移除typelist中的第一个类型 ...... */
        // 泛化版本:只声明,用来引出特化版本
        // 注意:只有TypeList中类类型为空时,才会调用泛化版本
        template <typename TypeList>
        class pop_front;
        // 特化版本:用来移除typelist中的第一个类型
        template <typename FirstType, typename... OtherTypes>
        class pop_front<typelist<FirstType, OtherTypes...>>
        {
        public:
            using type = typelist<OtherTypes...>;
        }; 
        
        /* ...... push_front类模板:给typelist头插一个类型 ...... */
        // 泛化版本:只声明,用来引出特化版本
        template <typename TypeList, typename insertType>
        class push_front;
        // 特化版本:用来给typelist头插一个类型
        template <typename... srcTypes, typename insertType>
        class push_front<typelist<srcTypes...>, insertType>
        {
        public:
            using type = typelist<insertType, srcTypes...>;
        };
        
        /* ...... push_back类模板:给typelist尾插一个类型 ...... */
        // 泛化版本:只声明,用来引出特化版本
        template <typename TypeList, typename insertType>
        class push_back;
        // 特化版本:用来给typelist尾插一个类型
        template <typename... srcTypes, typename insertType>
        class push_back<typelist<srcTypes...>, insertType>
        {
        public:
        	using type = typelist<srcTypes..., insertType>;
        };
    
        /* ...... replace_front类模板:替换typelist首个类类型 ...... */
        // 泛化版本:只声明,用来引出特化版本
        template <typename TypeList, typename replaceType>
        class replace_front;
        // 特化版本:替换typelist首个类类型
        template <typename FirstType, typename... OtherTypes, typename replaceType>
        class replace_front<typelist<FirstType, OtherTypes...>, replaceType>
        {
        public:
            using type = typelist<replaceType, OtherTypes...>;
        };
    
        void test()
        {
            using tylist1 = _nmsp_baseInterface::typelist<int, float, double, char, string>;
            cout << _nmsp_baseInterface::size<tylist1>::count << endl;
            cout << typeid(_nmsp_baseInterface::front<tylist1>::type).name() << endl;
    
            using tylist1_deletefront = _nmsp_baseInterface::pop_front<tylist1>::type;
            cout << _nmsp_baseInterface::size<tylist1_deletefront>::count << endl;
            cout << typeid(_nmsp_baseInterface::front<tylist1_deletefront>::type).name() << endl;
    
            using tylist1_frontinsert = _nmsp_baseInterface::push_front<tylist1, short>::type;
            cout << _nmsp_baseInterface::size<tylist1_frontinsert>::count << endl;
            cout << typeid(_nmsp_baseInterface::front<tylist1_frontinsert>::type).name() << endl;
    
            using tylist1_backinsert = _nmsp_baseInterface::push_back<tylist1, size_t>::type;
            cout << _nmsp_baseInterface::size<tylist1_backinsert>::count << endl;
    
            using tylist1_replacefront = _nmsp_baseInterface::replace_front<tylist1, size_t>::type;
            cout << _nmsp_baseInterface::size<tylist1_replacefront>::count << endl;
            cout << typeid(_nmsp_baseInterface::front<tylist1_replacefront>::type).name() << endl;
    
            cout << "..........................................." << endl;
    
            using tylist2 = _nmsp_baseInterface::typelist<>;
            cout << _nmsp_baseInterface::size<tylist2>::count << endl;
            cout << _nmsp_baseInterface::is_empty<tylist2>::value << endl;
            /*
            cout << typeid(_nmsp_baseInterface::front::type).name() << endl;
            //	Error:因_nmsp_baseInterface::front此时调用的是泛化版本的front类模板
            //,其内部并未定义type故会报错
    
            using tylist2_delete1 = _nmsp_baseInterface::pop_front::type;
            //  Error:因_nmsp_baseInterface::pop_front此时调用的是泛化版本的pop_front类模板
            //,其内部并未定义type故会报错
            */ 
        }
    }
    
    • 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
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    扩展的操作接口:
    根据索引号查询typelist中某个元素,即find类模板:

    在这里插入图片描述

    namespace _nmsp_extentInterface
    {
        /* ...... find类模板:找到typelist中,索引为index的类类型 ...... */
        // 泛化版本:实现递归实例化的过程
        // 如果index越界,则编译期会报错
        template <typename TypeList, size_t index>
        class find : public find<typename _nmsp_baseInterface::pop_front<TypeList>::type, index - 1>
        { };
        // 特化版本:用来作为递归继承的结束出口
        template <typename TypeList>
        class find<TypeList, 0> : public _nmsp_baseInterface::front<TypeList>
        { };
        
        void test()
        {
            using tylist1 = _nmsp_baseInterface::typelist<int, double, float, char, bool>;
            cout << typeid(_nmsp_extentInterface::find<tylist1, 0>::type).name() << endl;
            // 如果index越界,则编译期会报错 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    遍历typelist中sizeof最大的类类型,即get_maxsize类模板:

    在这里插入图片描述

    namespace _nmsp_extentInterface {
        /* ...... get_maxsize_type类模板:找到typelist中,sizeof最大的类类型 ...... */
        // 泛化版本:实递归实例化的过程
        template <typename TypeList>
        class get_maxsize_type
        {
        private:
            using firstElementType = typename _nmsp_baseInterface::front<TypeList>::type;
            using remainElements = typename _nmsp_baseInterface::pop_front<TypeList>::type;
            using first_remainElements_Type = typename get_maxsize_type<remainElements>::type;
        public:
            using type = typename std::conditional<(sizeof(firstElementType) >= sizeof(first_remainElements_Type)), firstElementType, first_remainElements_Type>::type;
        };
        // 特化版本:用来作为递归结束的出口
        template <>
        class get_maxsize_type<_nmsp_baseInterface::typelist<>>
        {
        public:
            using type = char;
        };
        
        void test()
        {
            using tylist1 = _nmsp_baseInterface::typelist<int, double, float, char, bool>; 
            cout << typeid(_nmsp_extentInterface::get_maxsize_type<tylist1>::type).name() << endl; 
        }
    }
    
    • 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
    反转typelist,即reverse类模板:

    在这里插入图片描述

    namespace _nmsp_extentInterface
    {    
        /* ...... reverse类模板:将typelist中的类类型按现有顺序反转 ...... */
        // 泛化版本:是声明不定义,用来引出特化版本
        template <typename TypeList, bool = _nmsp_baseInterface::is_empty<TypeList>::value>
        class reverse;
        // 特化版本1:
        template <typename TypeList>
        class reverse<TypeList, false>
        {
        private:
            using firstElementType = typename _nmsp_baseInterface::front<TypeList>::type;
            using reversed_results = typename reverse<typename _nmsp_baseInterface::pop_front<TypeList>::type>::type;
        public:
        	using type = typename _nmsp_baseInterface::push_back<reversed_results, firstElementType>::type;
        };
        // 特化版本2:
        template <typename TypeList>
        class reverse<TypeList, true>
        {
        public:
            using type = TypeList;
        };
        
        void test()
        {
            using tylist1 = _nmsp_baseInterface::typelist<int, double, float, char, bool>; 
            using reversed_tylist1 = _nmsp_extentInterface::reverse<tylist1>::type;
            cout << typeid(_nmsp_baseInterface::front<reversed_tylist1>::type).name() << endl; 
        }
    }
    
    • 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

    tuple的实现:(递归组合实现)

    元组tuple是一个可以装不同类型元素和数组/容器。

    #include 
    #include  
    using namespace std;
    
    namespace _nmsp_tuple_baseInterface
    {
        /* .. 该函数模板用来识别类中是否含有tuple_fun()函数,即判断该类是否时tuple类 .. */
        template <typename T, typename U = std::void_t<>>
        class HasMemTupleFunc : public std::false_type
        { };
        // 特化版本:std::declval().tuple_func()可在不构建T类对象的情况下,达到构建了对象的效果
        template <typename T>
        class HasMemTupleFunc<T, std::void_t<decltype(std::declval<T>().tuple_func())>> : public std::true_type
        { };
        /* ......................................... */
    
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename... Types>
        class tuple;
    
        // 特化版本1:用来递归实例化的过程
        template <typename First, typename... Others>
        class tuple<First, Others...>
        {
            public:
            First first;
            tuple<Others...> others;
            public:
            // 默认构造函数:
            tuple()
            {
                cout << "tuple::tuple()" << endl;
            }
            // 有参构造函数(模板):
            // 这里使用“万能引用 + std::forward”,可还原原始传入的实参的左右值属性,即实现“完美转发”
            // 通过“完美转发”,可在拷贝过程中,对右值进行移动拷贝,故可提高程序的效率
            template <typename _First, typename... _Others
            , typename = std::enable_if_t< !HasMemTupleFunc<_First>::value >>
                tuple(_First&& _first, _Others&&... _others) : first(std::forward<_First>(_first))
                , others(std::forward<_Others>(_others)...)
            {
                cout << "tuple::tuple(_First&& _first, _Others&&... _others)" << endl;
            }
    
            // 拷贝构造函数: 
            /*
    		// 如果形参用const修饰,编译器会报错
    		// 原因:本该在拷贝构造时调用该函数,结果编译器却调用了有参构造函数,导致出现错误
    		tuple(const tuple& _tuple) : first(_tuple.first), others(_tuple.others)
    		{
    			cout << "tuple::tuple(const tuple& _tuple)" << endl;
    		}
    		*/
            /*
    		// 解决方法,将形参的const修饰符,拿掉
    		// 但存在新的问题:无法正常拷贝“常量tuple对象”或“显式转换得到的tuple对象”
    		tuple(tuple& _tuple) : first(_tuple.first), others(_tuple.others)
    		{
    			cout << "tuple::tuple(const tuple& _tuple)" << endl;
    		}
    		*/
            // 解决方法:
            // 1、在tuple类中引入一个tuple类专属的成员函数,用来识别tuple类
            // 2、在有参构造函数(模板)的模板参数列表中,加入一个模板参数
            // typename = std::enable_if_t::value
            // ,表示只有在传入的第一个实参不是tuple类型时,才会调用高函数
            tuple(const tuple<First, Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
                cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
    
            // 拷贝构造函数模板:
            // 当调用拷贝构造时,_First参数类型与First不一致时,则会调用“拷贝构造函数模板”
            template <typename _First, typename... _Others>
            tuple(const tuple<_First, _Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
                cout << "tuple<_First, _Others...>::tuple(const tuple<_First, _Others...>& _tuple)" << endl;
            }
            public:
            void tuple_func() {}
        };
    
        // 特化版本2:作为递归结束的出口
        template <>
        class tuple<>
        {
            public:
            tuple() { cout << "tuple<>::tuple()" << endl; }
            tuple(const tuple<>&) { cout << "tuple<>::tuple(const tuple<>&)" << endl; }
        };
    
    
        /* 通过get函数得到tuple中的第index个元素:*/
        // 泛化版本:用于递归实例化展开
        template <size_t index>
        class GetHelper
        {
            public:
            template <typename First, typename... Others>
            static auto getHelper(const tuple<First, Others...>& _tuple)
            {
                return GetHelper<index - 1>::getHelper(_tuple.others);
            }
        };
        // 特化版本:用于递归结束的出口
        template <>
        class GetHelper<0>
        {
            public:
            template <typename First, typename... Others>
            static auto getHelper(const tuple<First, Others...>& _tuple)
            {
                return _tuple.first;
            }
        };
        // 函数模板:用于对外调用的接口
        template <size_t index, typename... Types>
        auto get(const tuple<Types...>& _tuple)
        {
            return GetHelper<index>::getHelper(_tuple);
        }
    
    
        /* 通过make_tuple函数,可将不同类型的数据打包转化为tuple类型:*/
        template <typename... Types>
        auto make_tuple(Types&&... args)  // 形参是万能引用
        {
            return tuple<std::decay_t<Types>...>(std::forward<Types>(args)...);
        }
        // 这里make_tuple的类型推导技术:可根据传入的实参自动推导出元素的类型,并将“退化”后的类型放入tuple中
    
    
        void test()
        {
            tuple<int, float, double> mytuple1;
            cout << "*********************************************" << endl;
    
            tuple<int, float, double, string> mytuple2(int(1), float(2.1), double(3.5), string("hello"));
            cout << "*********************************************" << endl;
    
            tuple<int, float, double, string> mytuple3(mytuple2);
            cout << "...当mytuple4==>First==double、mytuple2==>First==int时,类型不一致时,需通过调用“拷贝构造函数模板”完成拷贝 ..." << endl;
            tuple<double, float, double, string> mytuple4(mytuple2);
            cout << "*********************************************" << endl;
    
            tuple<double> mytuple5(3.5);
            cout << "---------------------------------------------" << endl;
            // 这里第三个参数的拷贝,调用的是“拷贝构造函数模板”
            tuple<int, float, tuple<double>> mytuple6(int(1), float(2.1), mytuple5);
    
            cout << "---------------------------------------------" << endl;
    
            tuple<int, double> mytuple5_(3.5);
            tuple<tuple<int, double>> mytuple6_(mytuple5);
            // 这里注意:如果嵌套的tuple中,存在两个及以上的类型,则会报错,原因是调用拷贝构造函数模板时
            //,First == tuple 与 _First == int,不一致导致的
            /* 这里需要进一步有待完善。。。 */
            cout << "*********************************************" << endl;
    
            cout << get<0>(mytuple6) << endl;
            cout << get<1>(mytuple6) << endl;
            cout << get<0>(get<2>(mytuple6)) << endl;
            cout << "*********************************************" << endl;
    
            auto mytuple7 = _nmsp_tuple_baseInterface::make_tuple(int(1), float(2.1), double(3.5), string("hello"));
            cout << "*********************************************" << endl; 
        }
    }
    
    namespace _nmsp_tuple_extentInterface
    {
        /* pop_front_type类模板:从tuple中移除第一个“类型” */
        // 泛化版本:
        template <typename Tuple>
        class pop_front_type;
        // t特化版本:
        template <typename First, typename... Others>
        class pop_front_type<_nmsp_tuple_baseInterface::tuple<First, Others...>>
        {
            public:
            using type = _nmsp_tuple_baseInterface::tuple<Others...>;
        }; 
    
        /* push_front函数模板:向tuple的头插一个元素 */ 
        // 普通实现方法:
        template <typename... Types, typename insertType>
        auto push_front(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple, const insertType& newElement)
        { 
            return _nmsp_tuple_baseInterface::tuple<insertType, Types...>(newElement, _tuple);
        }
        // 递归方法: 
        // 1、递归结束的出口
        template <typename insertType>
        auto push_front_recursive(const _nmsp_tuple_baseInterface::tuple<>& _tuple, const insertType& newElement)
        {
            return _nmsp_tuple_baseInterface::tuple<insertType>(newElement);
        }
        // 2、递归实例化的过程:
        template <typename First, typename... Others, typename insertType>
        auto push_front_recursive(const _nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple, const insertType& newElement)
        {
            return _nmsp_tuple_baseInterface::tuple<insertType, First, Others...>(newElement, push_front_recursive(_tuple.others, _tuple.first));
        }
    
        /* push_back函数模板:向tuple的头插一个元素 */ 
        /*
    	//普通实现写法:不支持这种写法
    	template 
    	auto push_back(const _nmsp_tuple_baseInterface::tuple& _tuple, const insertType& newElement)
    	{
    		return _nmsp_tuple_baseInterface::tuple(_tuple, newElement);
    	}
    	*/ 
        // 递归方法: 
        // 1、递归结束的出口
        template <typename insertType>
        auto push_back(const _nmsp_tuple_baseInterface::tuple<>& _tuple, const insertType& newElement)
        {
            return _nmsp_tuple_baseInterface::tuple<insertType>(newElement);
        }
        // 2、递归实例化的过程:
        template <typename First, typename... Others, typename insertType>
        auto push_back(const _nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple, const insertType& newElement)
        {
            return _nmsp_tuple_baseInterface::tuple<First, Others..., insertType>(_tuple.first, push_back(_tuple.others, newElement));
        }
    
        /* pop_front函数模板:从tuple中移除第一个元素 */
        template <typename Tuple>
        auto pop_front(const Tuple& _tuple)
        {	
            return _tuple.others;
        }
    
        /* reverse函数模板:反转一个tuple中的元素顺序 */ 
        // 递归方法:
        // 1、递归结束的出口
        auto reverse(const _nmsp_tuple_baseInterface::tuple<>&)
        {
            return _nmsp_tuple_baseInterface::tuple<>();
        }
        // 2、递归的过程 
        template <typename First, typename... Others>
        auto reverse(_nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple)
        {
            return push_back(reverse(_tuple.others), _tuple.first);
        }
        // 结合IntegerSequence_Reverse,实现reverse:   
        namespace IntegerSequenceReverse
        {
            /* 定义 IntegerSequence_pushBack 类模板(泛化和特化版本),用来实现“尾插”的功能: */
            template <typename T, size_t newElement>
            class IntegerSequence_pushFront;   // 因不使用泛化版本,故只声明不定义
    
            template <typename T, size_t... Elements, size_t newElement>
            class IntegerSequence_pushFront<std::integer_sequence<T, Elements...>, newElement>
            {
                public:
                using type = std::integer_sequence<T, newElement, Elements...>;
            };
            /* .................................... */
    
            /* 自定义 Integer_Sequence 类模板(泛化和特化版本),用来实现make_integer_sequence的功能:*/
            // 泛化版本:
            template <typename T, size_t N>
            class Integer_Sequence_Reverse
            {
                public:
                // 依次遍历出N-1、...、3、2、1、0,并逐个通过IntegerSequence_pushBack尾插
                using type = typename IntegerSequence_pushFront<typename Integer_Sequence_Reverse<T, N - 1>::type, N - 1>::type;
            };
            // 特化版本:
            template <typename T>
            class Integer_Sequence_Reverse<T, 1>
            {
                public:
                using type = std::integer_sequence<T, 0>;
            };
            /* .................................... */
    
            /* 定义别名模板:*/
            template <typename T, size_t N>
            using Integer_Sequence_Reverse_T = typename Integer_Sequence_Reverse<T, N>::type;
            /* .................................... */
        }  
        template <typename... Types, size_t... integralSequence>
        auto reverseHelper(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple, std::integer_sequence<size_t, integralSequence...>)
        {
            // 这里将传入的逆序整形序列,作为get中的index,进而实现逆序
            return make_tuple(_nmsp_tuple_baseInterface::get<integralSequence>(_tuple)...);
        }
        template <typename... Types>
        auto reverse_(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple)
        {
            // sizeof...(Types) == N --> IntegerSequenceReverse::Integer_Sequence_Reverse_T --> std::integer_sequence
            // IntegerSequenceReverse::Integer_Sequence_Reverse_T() --> 产生一个std::integer_sequence()临时对象
            return reverseHelper(_tuple, IntegerSequenceReverse::Integer_Sequence_Reverse_T<size_t, sizeof...(Types)>());
        }
    	 
        void test()
        {
            _nmsp_tuple_baseInterface::tuple<float, double, string> mytuple1(float(1.2), double(2.5), string("hello"));
            cout << typeid(typename pop_front_type<decltype(mytuple1)>::type).name() << endl;
            cout << "**********************************" << endl;
    
            // auto == _nmsp_tuple_baseInterface::tuple 
            auto mytuple2 = _nmsp_tuple_extentInterface::push_front(mytuple1, int(1));
            cout << ".........................................." << endl;
            auto mytuple3 = _nmsp_tuple_extentInterface::push_front_recursive(mytuple1, int(1));
            cout << "**********************************" << endl;
    
            // auto == _nmsp_tuple_baseInterface::tuple 
            auto mytuple4 = _nmsp_tuple_extentInterface::push_back(mytuple1, int(1));
            cout << "**********************************" << endl;
    
            auto mytuple5 = _nmsp_tuple_extentInterface::pop_front(mytuple3);
            cout << "**********************************" << endl;
    
            auto mytuple6 = _nmsp_tuple_extentInterface::reverse(mytuple2);
            cout << typeid(mytuple6).name() << endl;
            cout << "**********************************" << endl;
    
            // 测试Integer_Sequence_Reverse_T:
            IntegerSequenceReverse::Integer_Sequence_Reverse_T<int, 5> tmpObj;
            cout << typeid(decltype(tmpObj)).name() << endl;
            // 利用reverse_实现tuple的反转:
            auto mytuple7 = _nmsp_tuple_extentInterface::reverse_(mytuple2);
            cout << typeid(mytuple6).name() << endl;
            cout << "**********************************" << endl;
        }
    }
    
    int main()
    { 
        _nmsp_tuple_baseInterface::test();
        _nmsp_tuple_extentInterface::test();
    
        return 0;
    }
    
    • 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
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339

    元组的基础代码:

    #include 
    #include  
    using namespace std;
    
    namespace _nmsp
    {
        /* .. 该函数模板用来识别类中是否含有tuple_fun()函数,即判断该类是否时tuple类 .. */
        template <typename T, typename U = std::void_t<>>
        class HasMemTupleFunc : public std::false_type
        { };
        // 特化版本:std::declval().tuple_func()可在不构建T类对象的情况下,达到构建了对象的效果
        template <typename T>
        class HasMemTupleFunc<T, std::void_t<decltype(std::declval<T>().tuple_func())>> : public std::true_type
        { };
        /* ......................................... */
    
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename... Types>
        class tuple;
    
        // 特化版本1:用来递归实例化的过程
        template <typename First, typename... Others>
        class tuple<First, Others...>
        {
        public:
            First first;
            tuple<Others...> others;
        public:
            // 默认构造函数:
            tuple()
            {
            	cout << "tuple::tuple()" << endl;
            }
            // 有参构造函数(模板):
            // 这里使用“万能引用 + std::forward”,可还原原始传入的实参的左右值属性,即实现“完美转发”
            // 通过“完美转发”,可在拷贝过程中,对右值进行移动拷贝,故可提高程序的效率
            template <typename _First, typename... _Others
            , typename = std::enable_if_t< !HasMemTupleFunc<_First>::value >>
            tuple(_First&& _first, _Others&&... _others) : first(std::forward<_First>(_first))
            , others(std::forward<_Others>(_others)...)
            {
            	cout << "tuple::tuple(_First&& _first, _Others&&... _others)" << endl;
            }
    
            // 拷贝构造函数: 
            /*
            // 如果形参用const修饰,编译器会报错
            // 原因:本该在拷贝构造时调用该函数,结果编译器却调用了有参构造函数,导致出现错误
            tuple(const tuple& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
            */
            /*
            // 解决方法,将形参的const修饰符,拿掉
            // 但存在新的问题:无法正常拷贝“常量tuple对象”或“显式转换得到的tuple对象”
            tuple(tuple& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
            */
            // 解决方法:
            // 1、在tuple类中引入一个tuple类专属的成员函数,用来识别tuple类
            // 2、在有参构造函数(模板)的模板参数列表中,加入一个模板参数
            // typename = std::enable_if_t::value
            // ,表示只有在传入的第一个实参不是tuple类型时,才会调用高函数
            tuple(const tuple<First, Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
    
            // 拷贝构造函数模板:
            // 当调用拷贝构造时,_First参数类型与First不一致时,则会调用“拷贝构造函数模板”
            template <typename _First, typename... _Others>
            tuple(const tuple<_First, _Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple<_First, _Others...>::tuple(const tuple<_First, _Others...>& _tuple)" << endl; 
            }
        public:
        	void tuple_func() {}
        };
    
        // 特化版本2:作为递归结束的出口
        template <>
        class tuple<>
        {
        public:
            tuple() { cout << "tuple<>::tuple()" << endl; }
            tuple(const tuple<>&) { cout << "tuple<>::tuple(const tuple<>&)" << endl; }
        };
    
    
        /* 通过get函数得到tuple中的第index个元素:*/
        // 泛化版本:用于递归实例化展开
        template <size_t index>
        class GetHelper
        {
        public:
            template <typename First, typename... Others>
            static auto getHelper(const tuple<First, Others...>& _tuple)
            {
            	return GetHelper<index - 1>::getHelper(_tuple.others);
            }
        };
        // 特化版本:用于递归结束的出口
        template <>
        class GetHelper<0>
        {
        public:
            template <typename First, typename... Others>
            static auto getHelper(const tuple<First, Others...>& _tuple)
            {
                return _tuple.first;
            } 
        };
        // 函数模板:用于对外调用的接口
        template <size_t index, typename... Types>
        auto get(const tuple<Types...>& _tuple)
        {
        	return GetHelper<index>::getHelper(_tuple);
        }
    
    
        /* 通过make_tuple函数,可将不同类型的数据打包转化为tuple类型:*/
        template <typename... Types>
        auto make_tuple(Types&&... args)  // 形参是万能引用
        {
        	return tuple<std::decay_t<Types>...>(std::forward<Types>(args)...);
        }
        // 这里make_tuple的类型推导技术:可根据传入的实参自动推导出元素的类型,并将“退化”后的类型放入tuple中
    }
    
    
    int main()
    {
        _nmsp::tuple<int, float, double> mytuple1;
        cout << "*********************************************" << endl;
    
        _nmsp::tuple<int, float, double, string> mytuple2(int(1), float(2.1), double(3.5), string("hello"));
        cout << "*********************************************" << endl;
    
        _nmsp::tuple<int, float, double, string> mytuple3(mytuple2);
        cout << "...当mytuple4==>First==double、mytuple2==>First==int时,类型不一致时,需通过调用“拷贝构造函数模板”完成拷贝 ..." << endl;
        _nmsp::tuple<double, float, double, string> mytuple4(mytuple2);
        cout << "*********************************************" << endl;
    
        _nmsp::tuple<double> mytuple5(3.5);
        cout << "---------------------------------------------" << endl;
        // 这里第三个参数的拷贝,调用的是“拷贝构造函数模板”
        _nmsp::tuple<int, float, _nmsp::tuple<double>> mytuple6(int(1), float(2.1), mytuple5);
    
        cout << "---------------------------------------------" << endl;
    
        _nmsp::tuple<int, double> mytuple5_(3.5);
        _nmsp::tuple<_nmsp::tuple<int, double>> mytuple6_(mytuple5);
        // 这里注意:如果嵌套的tuple中,存在两个及以上的类型,则会报错,原因是调用拷贝构造函数模板时
        //,First == _nmsp::tuple 与 _First == int,不一致导致的
        /* 这里需要进一步有待完善。。。 */
        cout << "*********************************************" << endl;
    
        cout << _nmsp::get<0>(mytuple6) << endl;
        cout << _nmsp::get<1>(mytuple6) << endl;
        cout << _nmsp::get<0>(_nmsp::get<2>(mytuple6)) << endl;
        cout << "*********************************************" << endl;
    
        auto mytuple7 = _nmsp::make_tuple(int(1), float(2.1), double(3.5), string("hello"));
        cout << "*********************************************" << endl;
    
        return 0;
    }
    
    • 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
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170

    “泛化、特化、构造函数”的实现:

    #include 
    #include 
    using namespace std;
    
    namespace _nmsp
    {
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename... Types>
        class tuple;
    	
        // 特化版本1:用来递归实例化的过程
        template <typename First, typename... Others>
        class tuple<First, Others...>
        {
        public:
            First first;
            tuple<Others...> others;
        public:
            // 默认构造函数:
            tuple() 
            {
            	cout << "tuple::tuple()" << endl;
            }
            // 有参构造函数:
            // 这里使用“万能引用 + std::forward”,可还原原始传入的实参的左右值属性,即实现“完美转发”
            // 通过“完美转发”,可在拷贝过程中,对右值进行移动拷贝,故可提高程序的效率
            template <typename _First, typename... _Others>
            tuple(_First&& _first, _Others&&... _others) : first(std::forward<_First>(_first)), others(std::forward<_Others>(_others)...)
            {
            	cout << "tuple::tuple(_First&& _first, _Others&&... _others)" << endl;
            	cout << first << endl;
            }
        };
    	
        // 特化版本2:作为递归结束的出口
        template <>
        class tuple<>
        {
        public:
            tuple() { cout << "tuple<>::tuple()" << endl; }
            tuple(const tuple<>&) { cout << "tuple<>::tuple(const tuple<>&)" << endl; }
        };
    }
    
    • 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

    “拷贝构造函数、拷贝构造函数模板”的实现:

    #include 
    #include  
    using namespace std;
    
    namespace _nmsp
    {
        /* .. 该函数模板用来识别类中是否含有tuple_fun()函数,即判断该类是否时tuple类 .. */
        template <typename T, typename U = std::void_t<>>
        class HasMemTupleFunc : public std::false_type
        { };
        // 特化版本:std::declval().tuple_func()可在不构建T类对象的情况下,达到构建了对象的效果
        template <typename T>
        class HasMemTupleFunc<T, std::void_t<decltype(std::declval<T>().tuple_func())>> : public std::true_type
        { };
        /* ......................................... */
    
        // 泛化版本:只声明不定义,用来引出特化版本
        template <typename... Types>
        class tuple;
    
        // 特化版本1:用来递归实例化的过程
        template <typename First, typename... Others>
        class tuple<First, Others...>
        {
        public:
            First first;
            tuple<Others...> others;
        public:
            // 默认构造函数:
            tuple()
            {
            	cout << "tuple::tuple()" << endl;
            }
            // 有参构造函数(模板):
            // 这里使用“万能引用 + std::forward”,可还原原始传入的实参的左右值属性,即实现“完美转发”
            // 通过“完美转发”,可在拷贝过程中,对右值进行移动拷贝,故可提高程序的效率
            template <typename _First, typename... _Others, typename = std::enable_if_t< !HasMemTupleFunc<_First>::value>>
            tuple(_First&& _first, _Others&&... _others) : first(std::forward<_First>(_first)), others(std::forward<_Others>(_others)...)
            {
            	cout << "tuple::tuple(_First&& _first, _Others&&... _others)" << endl;
            }
    
            // 拷贝构造函数: 
            /*
            // 如果形参用const修饰,编译器会报错
            // 原因:本该在拷贝构造时调用该函数,结果编译器却调用了有参构造函数,导致出现错误
            tuple(const tuple& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
            */
            /*
            // 解决方法,将形参的const修饰符,拿掉
            // 但存在新的问题:无法正常拷贝“常量tuple对象”或“显式转换得到的tuple对象”
            tuple(tuple& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
            */
            // 解决方法:
            // 1、在tuple类中引入一个tuple类专属的成员函数,用来识别tuple类
            // 2、在有参构造函数(模板)的模板参数列表中,加入一个模板参数`typename = std::enable_if_t::value>`,表示只有在传入的第一个实参不是tuple类型时,才会调用该函数
            tuple(const tuple<First, Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
            	cout << "tuple::tuple(const tuple& _tuple)" << endl;
            }
    
            // 拷贝构造函数模板:
            // 当调用拷贝构造时,两个_tuple的_First参数类型与First不一致时,则会调用“拷贝构造函数模板”
            template <typename _First, typename... _Others>
            tuple(const tuple<_First, _Others...>& _tuple) : first(_tuple.first), others(_tuple.others)
            {
                cout << "tuple<_First, _Others...>::tuple(const tuple<_First, _Others...>& _tuple)" << endl; 
            }
        public:
        	void tuple_func() {}
        };
    
        // 特化版本2:作为递归结束的出口
        template <>
        class tuple<>
        {
        public:
            tuple() { cout << "tuple<>::tuple()" << endl; }
            tuple(const tuple<>&) { cout << "tuple<>::tuple(const tuple<>&)" << endl; }
        };
    }
    
    • 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
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    注意“拷贝构造函数”和“拷贝构造函数模板”的区别:(两者必须同时存在!!!)

    • “拷贝构造函数”被调用,说明:被拷贝的对象与待拷贝的对象的First参数类型是相同的。
    • “拷贝构造函数模板”被调用,则说明:被拷贝的对象与待拷贝的对象的First参数类型不同。

    实现获取tuple中元素的get接口:

    /* 通过get函数得到tuple中的第index个元素:*/
    // 泛化版本:用于递归实例化展开
    template <size_t index>
    class GetHelper
    {
    public:
        template <typename First, typename... Others>
        static auto getHelper(const tuple<First, Others...>& _tuple)
        {
            return GetHelper<index - 1>::getHelper(_tuple.others);
        }
    };
    // 特化版本:用于递归结束的出口
    template <>
    class GetHelper<0>
    {
    public:
        template <typename First, typename... Others>
        static auto getHelper(const tuple<First, Others...>& _tuple)
        {
            return _tuple.first;
        } 
    };
    // 函数模板:用于对外调用的接口
    template <size_t index, typename... Types>
    auto get(const tuple<Types...>& _tuple)
    {
        return GetHelper<index>::getHelper(_tuple);
    }
    
    • 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

    std::make_tuple的实现:

    /* 通过make_tuple函数,可将不同类型的数据打包转化为tuple类型:*/
    template <typename... Types>
    auto make_tuple(Types&&... args)  // 形参是万能引用
    {
    	return tuple<std::decay_t<Types>...>(std::forward<Types>(args)...);
    }
    
    // 这里make_tuple的类型推导技术:可根据传入的实参自动推导出元素的类型,并将“退化”后的类型放入tuple中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    算法:

    从tuple中移除第一个类型pop_front_type:

    /* pop_front_type类模板:从tuple中移除第一个类型 */
    // 泛化版本:
    template <typename Tuple>
    class pop_front_type;
    // t特化版本:
    template <typename First, typename... Others>
    class pop_front_type<_nmsp_tuple_baseInterface::tuple<First, Others...>>
    {
    public:
        using type = _nmsp_tuple_baseInterface::tuple<Others...>;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    向tuple的开头和结尾插入一个元素push_front、push_back:

    /* push_front函数模板:向tuple的头插一个元素 */ 
    // 普通实现方法:
    template <typename... Types, typename insertType>
    auto push_front(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple, const insertType& newElement)
    { 
    	return _nmsp_tuple_baseInterface::tuple<insertType, Types...>(newElement, _tuple);
    }
    // 递归方法: 
    // 1、递归结束的出口
    template <typename insertType>
    auto push_front_recursive(const _nmsp_tuple_baseInterface::tuple<>& _tuple, const insertType& newElement)
    {
    	return _nmsp_tuple_baseInterface::tuple<insertType>(newElement);
    }
    // 2、递归实例化的过程:
    template <typename First, typename... Others, typename insertType>
    auto push_front_recursive(const _nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple, const insertType& newElement)
    {
    	return _nmsp_tuple_baseInterface::tuple<insertType, First, Others...>(newElement, push_front_recursive(_tuple.others, _tuple.first));
    }
    
    /* push_back函数模板:向tuple的头插一个元素 */ 
    /*
    //普通实现写法:不支持这种写法
    template 
    auto push_back(const _nmsp_tuple_baseInterface::tuple& _tuple, const insertType& newElement)
    {
    	return _nmsp_tuple_baseInterface::tuple(_tuple, newElement);
    }
    */ 
    // 递归方法: 
    // 1、递归结束的出口
    template <typename insertType>
    auto push_back_(const _nmsp_tuple_baseInterface::tuple<>& _tuple, const insertType& newElement)
    {
        return _nmsp_tuple_baseInterface::tuple<insertType>(newElement);
    }
    // 2、递归实例化的过程:
    template <typename First, typename... Others, typename insertType>
    auto push_back_(const _nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple, const insertType& newElement)
    {
        return _nmsp_tuple_baseInterface::tuple<First, Others..., insertType>(_tuple.first, push_back(_tuple.others, newElement));
    }
    
    • 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

    从tuple中移除第一个元素pop_front:

    /* pop_front函数模板:从tuple中移除第一个元素 */
    template <typename Tuple>
    auto pop_front(const Tuple& _tuple)
    {	
        return _tuple.others;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    反转一个tuple中的元素顺序reverse:

    /* reverse函数模板:反转一个tuple中的元素顺序 */ 
    // 递归方法:
    // 1、递归结束的出口
    auto reverse(const _nmsp_tuple_baseInterface::tuple<>&)
    {
    	return _nmsp_tuple_baseInterface::tuple<>();
    }
    // 2、递归的过程 
    template <typename First, typename... Others>
    auto reverse(_nmsp_tuple_baseInterface::tuple<First, Others...>& _tuple)
    {
    	return push_back(reverse(_tuple.others), _tuple.first);
    }
    // 结合IntegerSequence_Reverse,实现reverse:   
    namespace IntegerSequenceReverse
    {
        /* 定义 IntegerSequence_pushBack 类模板(泛化和特化版本),用来实现“尾插”的功能: */
        template <typename T, size_t newElement>
        class IntegerSequence_pushFront;   // 因不使用泛化版本,故只声明不定义
    
        template <typename T, size_t... Elements, size_t newElement>
        class IntegerSequence_pushFront<std::integer_sequence<T, Elements...>, newElement>
        {
        public:
        	using type = std::integer_sequence<T, newElement, Elements...>;
        };
        /* .................................... */
    
        /* 自定义 Integer_Sequence 类模板(泛化和特化版本),用来实现make_integer_sequence的功能:*/
        // 泛化版本:
        template <typename T, size_t N>
        class Integer_Sequence_Reverse
        {
        public:
        	// 依次遍历出N-1、...、3、2、1、0,并逐个通过IntegerSequence_pushBack尾插
        	using type = typename IntegerSequence_pushFront<typename Integer_Sequence_Reverse<T, N - 1>::type, N - 1>::type;
        };
        // 特化版本:
        template <typename T>
        class Integer_Sequence_Reverse<T, 1>
        {
        public:
            using type = std::integer_sequence<T, 0>;
        };
        /* .................................... */
    
        /* 定义别名模板:*/
        template <typename T, size_t N>
        using Integer_Sequence_Reverse_T = typename Integer_Sequence_Reverse<T, N>::type;
        /* .................................... */
    }  
    template <typename... Types, size_t... integralSequence>
    auto reverseHelper(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple, std::integer_sequence<size_t, integralSequence...>)
    {
        // 这里将传入的逆序整型序列,作为get中的index,进而实现逆序
        return make_tuple(_nmsp_tuple_baseInterface::get<integralSequence>(_tuple)...);
    }
    template <typename... Types>
    auto reverse_(const _nmsp_tuple_baseInterface::tuple<Types...>& _tuple)
    {
        // sizeof...(Types) == N --> IntegerSequenceReverse::Integer_Sequence_Reverse_T --> std::integer_sequence
        // IntegerSequenceReverse::Integer_Sequence_Reverse_T() --> 产生一个std::integer_sequence()临时对象
        return reverseHelper(_tuple, IntegerSequenceReverse::Integer_Sequence_Reverse_T<size_t, sizeof...(Types)>());
    }
    
    • 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
  • 相关阅读:
    跟着 GPT-4 从0到1学习 Golang 并发机制(一)
    【C++学习】类与对象(上)
    延期公告 | 第五届“强网”拟态防御国际精英挑战赛
    java通过接口转发文件(上传下载)
    Matlab论文插图绘制模板第116期—带时间刻度的图
    Flutter 教程之如何从头开始设置 Flutter(2022 mac 版)
    使用docker-compose部署一个前端项目
    LeetCode:326(Python)—— 3 的幂
    14.在SpringBoot框架集成MyBatis(mapper、mapperscan、xml和dao分离)
    Linux学习笔记——查看帮助信息
  • 原文地址:https://blog.csdn.net/qq_44599368/article/details/133911346