C/C++ 萃取技术
【1】萃取技术基本概念演示
#include <iostream> using namespace std; namespace _nmsp1 { // 计算数组中元素的和值的函数模板 template <typename T> T funcsum(const T* begin, const T* end) { T sum{}; // 零初始化,如果数值型变量被初始化为0,指针型变量被初始化为nullptr,bool类型变量被初始化为false for (;;) { sum += (*begin); if (begin == end) break; ++begin; } return sum; } // 新引入模板参数 U 表示结果类型 template <typename U,typename T> U funcsum(const T* begin, const T* end) { U sum{}; // 零初始化,如果数值型变量被初始化为0,指针型变量被初始化为nullptr,bool类型变量被初始化为false for (;;) { sum += (*begin); if (begin == end) break; ++begin; } return sum; } } // 萃取技术及fixed traits(固定萃取)演示 // trait(萃取)技术用于对模板中的各种模板参数进行管理 // type traits:类型萃取 // 学习目的: // (a)了解标准库中许多trait(萃取)技术的实现方法 // (b) 灵活运用并组合这些实现方法,写出功能强大,优雅和实用的代码 int main() { // fixed traits(固定萃取):主要用于给定一种类型,萃取出另外一种类型; //(1)一个常规范例 // SumFixedTraits固定萃取类模板的作用:通过类型,得到另外一个类型 int myintarray1[] = { 10,15,20 }; int myintarray2[] = { 1000000000,1500000000,2000000000 }; // 10亿,15亿,20亿 char mychararray[] = "abc"; // 97,98,99 cout << _nmsp1::funcsum(&myintarray1[0], &myintarray1[2]) << endl; // int funcsum<int>(const int*,const int*); cout << _nmsp1::funcsum(&myintarray2[0], &myintarray2[2]) << endl; cout << (int)(_nmsp1::funcsum(&mychararray[0], &mychararray[2])) << endl; // char funcsum<char>(const char*,const char*); int myintarray1[] = { 10,15,20 }; int myintarray2[] = { 1000000000,1500000000,2000000000 }; // 10亿,15亿,20亿 char mychararray[] = "abc"; // 97,98,99 cout << _nmsp1::funcsum<__int64>(&myintarray1[0], &myintarray1[2]) << endl; // __int64 funcsum<__int64,int>(const int*,const int*); cout << _nmsp1::funcsum<__int64>(&myintarray2[0], &myintarray2[2]) << endl; // __int64 funcsum<__int64,int>(const int*,const int*); cout << (int)(_nmsp1::funcsum<int>(&mychararray[0], &mychararray[2])) << endl; // int funcsum<int,char>(const char*,const char*); return 0; }
#include <iostream> using namespace std; namespace _nmsp2 { // fixed traits类模板的泛化版本 template<typename T> struct SumFixedTraits; // 不需要实现代码,因为不需要用该版本进行实例化 // 各个fixed traits类模板的特化版本 // (1) 给进来char类型时,返回的是int类型 template <> struct SumFixedTraits<char> // char表示给定的是char类型 { using sumT = int; // 类型别名sumT代表int类型(返回类型) }; // (2) 给进来int类型时,返回的是__int64(long long/int64_t)类型 template <> struct SumFixedTraits<int> // int表示给进来的是int类型 { using sumT = __int64; // 类型别名sumT代表__int64类型(返回类型) }; // (3)....其他给进来的是某个类型,返回的是另外一个类型,可以任意扩展出多个SumFixedTraits类模板的特化版本 //----------------------- template <typename T> auto funcsum(const T* begin, const T* end) { using sumT = typename SumFixedTraits<T>::sumT; // 给进来一个类型(T),返回一个类型(sumT),这是fixed traits的运用 sumT sum{}; // 零初始化,如果数值型变量被初始化为0,指针型变量被初始化为nullptr,bool类型变量被初始化为false for (;;) { sum += (*begin); if (begin == end) break; ++begin; } return sum; } } // 萃取技术及fixed traits(固定萃取)演示 // trait(萃取)技术用于对模板中的各种模板参数进行管理 // type traits:类型萃取 // 学习目的: // (a)了解标准库中许多trait(萃取)技术的实现方法 // (b) 灵活运用并组合这些实现方法,写出功能强大,优雅和实用的代码 int main() { // fixed traits(固定萃取):主要用于给定一种类型,萃取出另外一种类型; int myintarray1[] = { 10,15,20 }; int myintarray2[] = { 1000000000,1500000000,2000000000 }; // 10亿,15亿,20亿 char mychararray[] = "abc"; // 97,98,99 cout << _nmsp2::funcsum(&myintarray1[0], &myintarray1[2]) << endl; // sumT funcsum<int>(const int*,const int*); cout << _nmsp2::funcsum(&myintarray2[0], &myintarray2[2]) << endl; // sumT funcsum<int>(const int*,const int*); cout << (int)(_nmsp2::funcsum(&mychararray[0], &mychararray[2])) << endl; // sumT funcsum<char>(const char*,const char*); return 0; }
【2】由容器类型萃取元素类型
#include <iostream> #include <vector> #include <list> using namespace std; namespace _nmsp1 { // template <class T> // struct vector // { // ..... // using value_type = T: // }; // 常规实现版本 /* // 泛化版本 template <typename T> struct GetEleType; // 特化版本 template <typename T> struct GetEleType<std::vector<T>> { using type = T; }; template <typename T> struct GetEleType<std::list<T>> { using type = T; }; template <typename T,std::size_t Size> // 这个特化版本增加了一个模板参数 struct GetEleType<T[Size]> // 萃取出数组元素个数 { using type = T; static const std::size_t size = Size; }; */ // 泛化版本,用泛化版本实现对容器类型的支持 template <typename T> struct GetEleType { using type = typename T::value_type; // 针对容器 }; // 针对数组的特化版本(内容不变) template <typename T, std::size_t Size> // 这个特化版本增加了一个模板参数 struct GetEleType<T[Size]> // 萃取出数组元素个数 { using type = T; static const std::size_t size = Size; }; // 别名模板: template <typename T> using EleType = typename GetEleType<T>::type; //--------------------------------------------------------------------------- // 函数模板 template <typename T> void PrintEleType(const T& container) { cout << "容器(数组)的元素类型为:" << typeid(GetEleType<T>::type).name() << endl; cout << "容器(数组)的元素类型为:" << typeid(EleType<T>).name() << endl; } } // 萃取技术及fixed traits(固定萃取)演示 int main() { //(3)通过容器(数组)类型萃取元素类型范例 //(3.1)用GetEleType类模板进行常规实现 //(3.2)引入函数模板PrintEleType //(3.2)GetEleType类模板的改进 cout << "vector<double>的元素类型为:" << typeid(_nmsp1::GetEleType< vector<double> >::type).name() << endl; cout << "list<int>的元素类型为:" << typeid(_nmsp1::GetEleType< list<int> >::type).name() << endl; cout << "float[45]的元素类型为:" << typeid(_nmsp1::GetEleType< float[45] >::type).name() << endl; cout << "float[45]的数组元素数量为:" << _nmsp1::GetEleType< float[45] >::size << endl; vector<double> mydblvec; _nmsp1::PrintEleType(mydblvec); list<int> myintlist; _nmsp1::PrintEleType(myintlist); float myfloatarr[45]; _nmsp1::PrintEleType(myfloatarr); cout << "vector<double>的元素类型为:" << typeid(vector<double>::value_type).name() << endl; return 0; }
【3】引用类型的移除与添加
#include <iostream> // 只在Debug(调试)模式下 #ifdef _DEBUG #ifndef DEBUG_NEW // 重新定义new运算符 #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) #define new DEBUG_NEW #endif #endif #include <boost/type_index.hpp> using namespace std; namespace _nmsp1 { template <class T1,class T2> void print_is_same() { cout << "T1类型为:" << typeid(T1).name() << endl; cout << "T2类型为:" << typeid(T2).name() << endl; cout << "T1类型和T2类型是否相等:" << std::is_same<T1, T2>() << endl; // // cout << "T1类型和T2类型是否相等:" << std::is_same<T1, T2>::value << endl; // 值为1则表示2个类型相等,值为0表示2个类型不等 // is_same是标准库中用于判断两个类型是否相同的类模板, // std::is_same<T1,T2>()写法写成std::is_same<T1,T2>::value效果也是一样的 } // c++14中定义了大量别名 // template<class T> // using remove_reference_t = typename remove_reference<T>::type; } namespace _nmsp2 { // 泛化版本 template <typename T> struct RemoveReference { using type = T; }; // 特化版本 template <typename T> struct RemoveReference<T&> { using type = T; }; template <typename T> struct RemoveReference<T&&> { using type = T; }; // 别名模板 template <typename T> using RemoveReference_t = typename RemoveReference<T>::type; } namespace _nmsp3 { template<typename T> struct AddLValueReference { using type = T&; // int && & ,引用折叠:有左值引用,结果必然为左值引用,所以type = int & }; template<typename T> using AddLValueReference_t = typename AddLValueReference<T>::type; // 实际上可以直接简化为using AddLValueReference_t = T&;,这样就不用定义AddLValueReference了; //---------------------------------------------------------------------------------------------------------------------------------- template<typename T> struct AddRValueReference { using type = T&&; }; template<typename T> using AddRValueReference_t = typename AddRValueReference<T>::type; // 实际上可以直接简化为using AddRValueReference_t = T&&;,这样就不用定义AddRValueReference了 } int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // 程序退出时检测内存泄漏并显示到“输出”窗口 //(4)引用类型的移除和增加 //(4.1)引用类型的移除 // std::remove_reference类模板 //(4.2)引用类型的增加:根据给定的类型来创建一个左值或者右值引用 // std::add_lvalue_reference类模板:给定一个类型,返回该类型对应的左值引用类型 // std::add_rvalue_reference类模板:给定一个类型,返回该类型对应的右值引用类型 // std::is_lvalue_reference和std::is_rvalue_reference类模板:判断某个类型是否是左值引用类型或者右值引用类型 std::remove_reference<int>::type a; std::remove_reference<int&>::type b; std::remove_reference<int&&>::type c; std::remove_reference_t<int> a; std::remove_reference_t<int &> b; std::remove_reference_t<int&&> c; _nmsp1::print_is_same<decltype(a), decltype(b)>(); _nmsp1::print_is_same<decltype(a), decltype(c)>(); int&& a2 = 12; // _nmsp2::RemoveReference_t<decltype(a2)> b2 = "dd"; // error C2440: “初始化”: 无法从“const char [3]”转换为“int” _nmsp2::RemoveReference_t<decltype(a2)> b2 = 125; int i = 64; int& c2 = i; _nmsp2::RemoveReference_t<decltype(c2)> d2 = 500; using boost::typeindex::type_id_with_cvr; cout << "b2= " << type_id_with_cvr<decltype(b2)>().pretty_name() << endl; cout << "d2= " << type_id_with_cvr<decltype(d2)>().pretty_name() << endl; int a = 15; std::add_lvalue_reference<decltype(a)>::type b = a; // b的类型为int & std::add_rvalue_reference<decltype(a)>::type c = 16; // c的类型为int && using btype = std::add_lvalue_reference_t<int>; // *_t是个别名模板 cout << std::is_same<int&, btype>() << endl; // 1 using ctype = std::add_rvalue_reference_t<int>; cout << std::is_lvalue_reference<btype>::value << endl; // 1 cout << std::is_rvalue_reference<ctype>::value << endl; // 1 std::add_rvalue_reference_t<int&> cc1 = a; // cc1类型为int &,这里涉及到引用折叠, &和&& 折叠后得到 & std::add_rvalue_reference_t<int&&> cc2 = 16; // cc2的类型为int &&,这里涉及到引用折叠,&&和&&折叠得到&& int anew = 15; _nmsp3::AddLValueReference_t<decltype(anew)> bnew = anew; // decltype(anew)的类型是int,bnew的类型为int & int&& anew2 = 16; _nmsp3::AddLValueReference_t<decltype(anew2)> bnew2 = anew; // decltype(anew2)的类型是int&&,bnew的类型为int & int argnew = 15; _nmsp3::AddRValueReference_t<decltype(argnew)> brgnew = 18; // brgnew的类型为int && int&& argnew2 = 15; _nmsp3::AddRValueReference_t<decltype(argnew2)> brgnew2 = 18; // brgnew2的类型为int && int tmpvalue = 16; int& argnew3 = tmpvalue; _nmsp3::AddRValueReference_t<decltype(argnew3)> brgnew3 = tmpvalue; // brgnew3的类型为int &,因为根据引用折叠规则,左值引用和右值引用遇到一起,结果是左值引用 return 0; }
【4】退化技术
#include <iostream> // 只在Debug(调试)模式下 #ifdef _DEBUG #ifndef DEBUG_NEW // 重新定义new运算符 #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) #define new DEBUG_NEW #endif #endif #include <boost/type_index.hpp> using namespace std; template<typename T> void myfunc(T tmprv) { cout << "---------------------begin------------------------" << endl; using boost::typeindex::type_id_with_cvr; cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; // 显示T类型 cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; // 显示tmprv类型 cout << "----------------------end-------------------------" << endl; } namespace _nmsp1 { //------------------------------------------------------------------------------------------------ // 去除引用修饰符 //------------------------------------------------------------------------------------------------ // 泛化版本 template <typename T> struct RemoveReference { using type = T; }; // 特化版本 template <typename T> struct RemoveReference<T&> { using type = T; }; template <typename T> struct RemoveReference<T&&> { using type = T; }; // 别名模板 template <typename T> using RemoveReference_t = typename RemoveReference<T>::type; //------------------------------------------------------------------------------------------------ // 去除const修饰符 //------------------------------------------------------------------------------------------------ // 泛化版本 template <typename T> struct RemoveConst { using type = T; }; // 特化版本 template <typename T> struct RemoveConst<const T> { using type = T; }; // 根据需要增加其他特化版本.... // 模板别名 template <typename T> using RemoveConst_t = typename RemoveConst<T>::type; //------------------------------------------------------------------------------------------------ // 去除const修饰符以及引用修饰符 //------------------------------------------------------------------------------------------------ template <typename T> struct RemoveCR :RemoveConst<typename RemoveReference<T>::type> // 把const和引用修饰符去掉 { }; // 模版别名 template <typename T> using RemoveCR_t = typename RemoveCR<T>::type; /*template <typename T> using RemoveCR_t = RemoveConst_t<typename RemoveReference_t<T>>;*/ //------------------------------------------------------------------------------------------------ // 退化技术 //------------------------------------------------------------------------------------------------ // 泛化版本 template<typename T> struct Decay :RemoveCR<T> { }; // 特化版本,处理数组,该特化版本没有继承任何父类 // 有边界数组转换成指针 template<typename T,std::size_t size> struct Decay<T[size]> { using type = T*; }; // 无边界数组转换成指针 template<typename T> struct Decay<T[]> { using type = T*; }; // 函数名变成函数指针等 template <typename T,typename... Args> struct Decay<T(Args...)> // 返回类型是T,参数Args.... { using type = T(*)(Args...); }; // 模版别名 template <typename T> using Decay_t = typename Decay<T>::type; // 测试函数 //------------------------------------------------------------------------------------------------ void testFunc() {} //------------------------------------------------------------------------------------------------ void testFunc2() { cout << "testFunc2()执行了" << endl; } } void rfunc() { cout << "rfunc执行了!" << endl; } extern int g_array[]; // 类型 int [] // 萃取技术及fixed traits(固定萃取)演示 int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // 程序退出时检测内存泄漏并显示到“输出”窗口 //(5)const修饰符的移除RemoveConst类模板,与C++标准库里std::remove_const比较类似 _nmsp1::RemoveConst_t<const int> nca = 15; // nca是int类型 nca = 18; // 可以给nca重新赋值 const int a = 16; const int& b = a; const int&& c = 18; int array[5] = { 1,2,3,4,5 }; myfunc(a); myfunc(b); myfunc(c); myfunc(array); myfunc(_nmsp1::testFunc); //(6)退化(decay)技术 // 退化:对于const int类型来说,int类型就是一种退化的表现 // const修饰符和&、&&修饰符被丢弃,数组类型变成指针类型,函数名变成了函数指针等,都是类型上的退化表现 // c++标准库:std::decay,该类模板的作用就是把类型退化掉(把类型中的修饰符丢弃掉) // 无边界数组,某个.cpp源文件中定义一个全局数组,如 int g_array[10]; int[10]; // extern int g_array[]; // 外部变量说明 // 基本概念: // a) 函数类型:由函数返回值和函数参数决定,testFunc2 代表的函数类型 void() // b) 可以利用函数指针指向某种函数类型,若要指向testFunc2,那么函数指针的类型就应该为void(*)() // c) 如果不为“函数名退化成函数指针”写一个Decay的特化版本,观察一些测试代码:给进去的是函数类型,返回的依旧是函数类型 std::decay<const int&>::type nb = 26; cout << "nb的类型为:" << typeid(decltype(nb)).name() << endl; // nb类型为int类型 _nmsp1::RemoveCR_t<const int&&> rcrobj = 16; // rcrobj为int类型,移除了const与引用属性 int arr[2] = { 1,2 }; _nmsp1::Decay<decltype(arr)>::type myarray; // 有边界数组转换成指针 cout << "myarray类型为:" << typeid(decltype(myarray)).name() << endl; _nmsp1::Decay<decltype(g_array)>::type myarray2; // 无边界数组转换成指针 cout << "myarray2类型为:" << typeid(decltype(myarray2)).name() << endl; void (*p) () = _nmsp1::testFunc2; // 定义了一个函数指针,指向testFunc2函数 p(); // 调用p指向的函数,调用的是testFunc2函数 _nmsp1::Decay<decltype(_nmsp1::testFunc2)>::type rfunc; // 表面看起来此代码行定义了一个函数类型的变量rfunc,实际理解成函数声明更好 // 类似于这种代码行的感觉:void rfunc(); cout << "rfunc类型为:" << typeid(decltype(rfunc)).name() << endl; rfunc(); // 调用rfunc函数 // 两种定义函数指针的方式 // _nmsp1::Decay<decltype(_nmsp1::testFunc2)>::type rfunc; _nmsp1::Decay_t<decltype(_nmsp1::testFunc2)> rfunc; cout << "rfunc类型为:" << typeid(decltype(rfunc)).name() << endl; rfunc = _nmsp1::testFunc2; // 给函数指针赋值 rfunc(); // 相当于调用了testFunc2函数 return 0; }
【5】策略技术
#include <iostream> using namespace std; namespace _nmsp1 { // 泛化版本 // SumFixedTraits类模板 template <typename T> struct SumFixedTraits; // 特化版本 char,转换为 int template<> struct SumFixedTraits<char> { using sumT = int; static sumT initValue() { return 0; } }; // 特化版本 int,转换为 __int64 template<> struct SumFixedTraits<int> { using sumT = __int64; static sumT initValue() { return 0; } }; // 特化版本 double,转换为 double template<> struct SumFixedTraits<double> { using sumT = double; static sumT initValue() { return 0.0; } }; //---------------------- // 泛化版本 template <typename T> struct MinFixedTraits; // 特化版本 template<> struct MinFixedTraits<int> { using sumT = int; // 求最小值,结果类型与元素类型相同即可,为了名字统一,都用sumT这个名字 static sumT initValue() { return INT_MAX; } // INT_MAX:整型最大值,任何一个数组元素都不会被这个值更大,因此可以顺利的找到数组元素中的最小值,参见MinPolicy::algorithm }; //---------------------- // 求和策略类以实现求和算法 template <typename sumT, typename T> struct SumPolicy { // 静态成员函数模板 static void algorithm(sumT& sum, const T& value) // 策略类的核心算法 { sum += value; // 求和 } }; //---------------------- //求最小值策略类 template <typename minT, typename T> struct MinPolicy { static void algorithm(minT& min, const T& value) { if (min > value) min = value; } }; //---------------------- // funcsum函数模板 // template <typename T, typename U = SumFixedTraits<T> > // T = char , U = SumFixedTraits<char> template <typename T, typename U = SumFixedTraits<T>, // typename V = SumPolicy template<class,class> class V = SumPolicy // 这里class也可以写成typename > auto funcsum(const T* begin, const T* end) { typename U::sumT sum = U::initValue(); // typename SumFixedTraits<char>::sumT sum = SumFixedTraits<char>::initValue(); // int sum = 0; for (;;) { V<U::sumT,T>::algorithm(sum, *begin); // 捋一下:T是数组成员类型,U是固定萃取(fixed traits)类模板, // 从中可以提取出结算的结果类型(U::sumT)以及结果的初值, // V是策略类模板,用于实现具体算法(求和,求最小值等) if (begin == end) break; ++begin; } return sum; } } // 策略(policy)技术中的算法策略 int main() { // 程序退出时检测内存泄漏并显示到“输出”窗口 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); //(1)常规范例:普通策略类 char mychararray[] = "abc"; cout << (int)(_nmsp1::funcsum(&mychararray[0], &mychararray[2])) << endl; //(2)常规范例:策略类模板 int myintarray1[] = { 10,15,20 }; cout << (int)(_nmsp1::funcsum<int, _nmsp1::SumFixedTraits<int>, _nmsp1::MinPolicy>(&myintarray1[0], &myintarray1[2])) << endl; cout << (int)(_nmsp1::funcsum<int, _nmsp1::MinFixedTraits<int>, _nmsp1::MinPolicy>(&myintarray1[0], &myintarray1[2])) << endl; //(3)萃取(trait)技术与策略(policy)技术的比较 // 两者之间的相同和不同之处: // a)两种技术都象一个中间件一样,夹在不同的功能代码之间,让代码之间的调用更加灵活 // b)萃取技术:给定一个类型,萃取出另外一个类型或者另外一个值(注重于类型或者指定) // 策略技术:给定一个类型,萃取出一个算法或者是一个不同的功能实现(注重于动作或者行为) // 因此,在书写策略类(类模板)的时候通常都需要包含成员函数以实现指定的行为 // 有时,萃取技术中也可能实现某些动作或者行为,所以从这个角度来讲,萃取技术与策略技术有时区分不是那么明显 // c)萃取技术一般通过一个类模板来实现,通常包含类模板的泛化版本和多个特化版本;策略技术用普通类或者类模板都可以实现 return 0; }
https://coppersun.blog.csdn.net/article/details/115417893