Templates<2>
Part:template specialized
Part1:template specialized
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <stdio.h> using namespace std; template <typename To,typename From> struct CastAndPrint { CastAndPrint(From f){ cout << (To)f <<endl; } }; template <typename To> struct CastAndPrint<To,const char*> { CastAndPrint(const char *s){ cout << (To)atoi(s) <<endl; } }; int main() { CastAndPrint<int,float>(1.232f); CastAndPrint<int,const char*>("67"); CastAndPrint<char,const char*>("67"); return 0; }
part2:Trait & Policy
(1) accumulation,可能的累积定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// // Created by Administrator on 2017/8/12. // #ifndef TP_CP15_ACCUM_ACCUMTRAITS_H #define TP_CP15_ACCUM_ACCUMTRAITS_H #include <iostream> template <typename T> class AccumulationTraits; template <> class AccumulationTraits<char> { public: typedef int AccT; }; template <> class AccumulationTraits<short> { public: typedef int AccT; }; template <> class AccumulationTraits<int> { public: typedef int AccT; }; template <> class AccumulationTraits<float> { public: typedef double AccT; }; #endif //TP_CP15_ACCUM_ACCUMTRAITS_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef TP_CP15_ACCUM_ACCUM2_H #define TP_CP15_ACCUM_ACCUM2_H #include <iostream> #include "accumtraits.h" template <typename T> typename AccumulationTraits<T>::AccT accum(T const*begin,T const*end) { typedef typename AccumulationTraits<T>::AccT AccT; AccT total = AccT(); while(begin!=end) { total += *begin; ++begin; } return total; } #endif //TP_CP15_ACCUM_ACCUM2_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include "accum2.h" using namespace std; int main() { int val[]{1,2,3,4,5}; cout << accum(val,val+5) <<endl; char val2[] = "AA"; cout << accum(val2,val2+3) <<endl; //130 return 0; }
(2) Trait 和 Policy为我们的程序提供一个用户可以编辑的模版接口
accumlation.h把所有的定义都写了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// // Created by Administrator on 2017/8/13. // #ifndef TP_CP15_ACCUMTRAITS2_ACCUMULATION_H #define TP_CP15_ACCUMTRAITS2_ACCUMULATION_H // ============================ Traits =============================== template <typename T> class AccumulationTraits; template <> class AccumulationTraits<char> { public: typedef int AccT; static AccT zero() { return 0;} }; template <> class AccumulationTraits<int> { public: typedef int AccT; static AccT zero() { return 0;} }; template <> class AccumulationTraits<short> { public: typedef int AccT; static AccT zero() { return 0;} }; template <> class AccumulationTraits<unsigned int> { public: typedef unsigned long AccT; static AccT zero() { return 0;} }; template <> class AccumulationTraits<float> { public: typedef float AccT; static AccT zero() { return 0.0f;} }; // ============================ Traits =============================== // define one Simple Policy for our defaults class SumPolicy { public: template <typename T1,typename T2> static void accumulate (T1 &total, T2 const &value) { total += value; } }; // template <typename T, typename Policy = SumPolicy, typename Traits = AccumulationTraits<T> > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum(T const*begin, T const *end) { AccT total = Traits::zero(); while (begin!=end) { Policy::accumulate(total,*begin); begin++; } return total; } }; #endif //TP_CP15_ACCUMTRAITS2_ACCUMULATION_H
main.cpp提供了2个新Policy接口,但是我们的乘法接口会出现问题,因为初值zero()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include "accumulation.h" // class DoubleAddPolicy { public: template <typename T1,typename T2> static void accumulate(T1 &total , T2 const &value) { total += 2 * value; } }; class MultPolicy { public: template <typename T1,typename T2> static void accumulate(T1 &total , T2 const &value) { total *= value; } }; using namespace std; int main() { int val[]{1,2,3,4,5,6}; cout << Accum<int>::accum(val,val+6) <<endl; char cval[] = "AA"; cout << Accum<char>::accum(cval,cval+2)<<endl; float fval[]{1.0,2.0,3.0,4.0,5.0}; cout << Accum<float>::accum(fval,fval+5)<<endl; cout << Accum<float,DoubleAddPolicy>::accum(fval,fval+5) <<endl; // but next result will is zero,because our value initialized to zero cout << Accum<float,MultPolicy>::accum(fval,fval+5) <<endl; return 0; }
Part3:Type function
(1) 确定容器元素类型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <vector> #include <stack> #include <typeinfo> #include <list> using namespace std; // class give the type size template <typename T> class TypeSize { public: static size_t const value = sizeof(T); }; // what element type in a container template <typename T> class ElementT; // basic template // vector<> template <typename T> class ElementT<vector<T>> { public: typedef T type; }; // list<> template <typename T> class ElementT<list<T>> { public: typedef T type; }; // stack<> template <typename T> class ElementT<stack<T>> { public: typedef T type; }; template <typename T> void print_element(T const &c) { cout << "Container of " << typeid(typename ElementT<T>::type).name() << endl; } // but lots of containers have it's own value_type,so we can use this method template <typename T> void print_valueType(T const &c) { cout << "Container of " << typeid(typename T::value_type).name()<< endl; } int main() { cout << TypeSize<char>::value <<endl; cout << TypeSize<short>::value <<endl; stack<int> s; vector<float> s2; print_element(s); print_element(s2); print_valueType(s2); return 0; }
(2) Why the container::value_type is import?
检查一个类型是类,还是不是类(SFINAE,substitution-failure-is-not-error,替换失败并非错误):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> template <typename T> class IsClassT { private: typedef struct {char a[2];} char2; template <typename C> static char test(int C::*); template <typename C> static char2 test(...); public: enum{Yes=sizeof(IsClassT<T>::test<T>(0)) == 1}; enum{No = !Yes}; }; template <typename T> void check() { if(IsClassT<T>::Yes) { std::cout << "IsClassT" <<std::endl; } else { std::cout << "!IsClassT" <<std::endl; } } class Data { }; int main() { check<int>(); check<Data>(); return 0; }
具体(SFINAE)解释程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> using namespace std; typedef struct char2 { char a[2]; }char2; template <typename T> char test(int T::*); template <typename T> char2 test(...); class Value { }; int main(int argc, char const *argv[]) { std::cout <<sizeof(char) <<endl; // 1 std::cout <<sizeof(char2) <<endl; // 2 std::cout << sizeof(test<int>(0)) << endl; // 2,select test(...) function std::cout << sizeof(test<Value>(0)) << endl; // 1,select test(int T::*) function return 0; }
Promotion trait:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef INC_15_2_4_IFTHENELSE_HPP_H #define INC_15_2_4_IFTHENELSE_HPP_H template <bool C, typename Ta , typename Tb> class IfThenElse; template <typename Ta,typename Tb> class IfThenElse<true,Ta,Tb> { public: typedef Ta value_type; }; template <typename Ta,typename Tb> class IfThenElse<false,Ta,Tb> { public: typedef Tb value_type; }; #endif //INC_15_2_4_IFTHENELSE_HPP_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef PROMOTE_HPP_H_ #define PROMOTE_HPP_H_ #include <vector> #include "ifthenelse.hpp" template <typename T1,typename T2> class Promotion; template <typename T1,typename T2> class Promotion { public: typedef typename IfThenElse<(sizeof(T1) > sizeof(T2)),T1,T2>::value_type value_type; }; template <typename T> class Promotion<T,T> { public: typedef T value_type; }; template <typename T1,typename T2> class Promotion<std::vector<T1>,std::vector<T2>> { public: typedef std::vector<typename Promotion<T1,T2>::value_type > value_type; }; template <typename T> class Promotion<std::vector<T>,std::vector<T>> { public: typedef std::vector<typename Promotion<T,T>::value_type > value_type; }; #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include "promote.hpp" #include <algorithm> using namespace std; template <typename T1,typename T2> typename Promotion<T1,T2>::value_type add(T1 val1,T2 val2) { return val1+val2; } template <typename T1,typename T2> typename Promotion<vector<T1>,vector<T2>>::value_type add(const vector<T1> &val1, const vector<T2> &val2) { typename Promotion<vector<T1>,vector<T2>>::value_type result; for(int i=0;i<val1.size();i++) { result.push_back(val1[i] + val2[i]); } return result; }; int main() { std::cout <<add(2,2.0f)<< std::endl; vector<int> val_01(3); fill(val_01.begin(),val_01.end(),1); vector<float> val_02(3); fill(val_02.begin(),val_02.end(),2.0f); auto result = add(val_01,val_02); // vector<float> for_each(result.begin(),result.end(),[](const float &val){cout << val << endl;}); return 0; }
Metaprogram:
<1>计算一个数的n次方
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> template <int S,int N> class pow { public: enum {result = S*pow<S,N-1>::result}; }; template <int S> class pow<S,0> { public: enum{result = 1}; }; template <int N> class pow<0,N> { public: enum{result}; }; template <> class pow<0,0> { public: enum{ result}; }; int main() { std::cout << pow<3,2>::result <<std::endl; // 3^2 std::cout << pow<2,2>::result <<std::endl; // 2^2 return 0; }
上面的代码依然可以用static int const result 代替:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> template <int S,int N> class pow { public: static const int result = S*pow<S,N-1>::result; }; template <int S> class pow<S,0> { public: static const int result = 1; }; template <int N> class pow<0,N> { public: static const int result = 0; }; template <> class pow<0,0> { public: static const int result = 0; }; int main() { std::cout << pow<3,2>::result <<std::endl; // 3^2 std::cout << pow<2,2>::result <<std::endl; // 2^2 return 0; }
不过static int 出来的数据永远是个左值。
<2>For循环展开:
(1)图形学dot()函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> template <int DIM, typename T> class DotProduct { public: static T result(T *a,T *b) { return (*a) * (*b) + DotProduct<DIM-1,T>::result(a+1,b+1); } }; template <typename T> class DotProduct<1,T> { public: static T result(T *a,T*b) { return (*a) * (*b); } }; int main() { float a[3] = {1,2,3}; float b[3] = {1,2,3}; std::cout << DotProduct<3,float>::result(a,b) << std::endl; return 0; }
(2)求数组合和数组乘积Accumulate
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
enum Accumulate_Type { ADD, Mutiply, }; template <int N,typename T,Accumulate_Type Type=ADD> class Accumulate { public: static T result(T *data) { if(Type == Accumulate_Type::ADD) return *data + Accumulate<N-1,T,Type>::result(data+1); return *data * Accumulate<N-1,T,Type>::result(data+1); } }; template <typename T,Accumulate_Type Type> class Accumulate<1,T,Type> { public: static T result(T *data) { return *data; } }; void testAccumulate() { float a[3] = {3,2,3}; std::cout << "Mutiply:"<<Accumulate<3,float,Accumulate_Type::Mutiply>::result(a)<<std::endl; std::cout << "Add:" <<Accumulate<3,float,Accumulate_Type::ADD>::result(a)<<std::endl; }
表达式模版:
一个疑问点:一个简单的模版类:
下面两种方案都一样:
Simple<T>& operator= (Simple<T> const &b) { std::cout << "operator= " << "a:" << this << "b:" <<&b <<std::endl; val = b.val; }
Simple& operator= (Simple const &b) { std::cout << "operator= " << "a:" << this << " b:" <<&b <<std::endl; val = b.val; }
类定义全部定义:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
template <typename T> class Simple { public: T val; Simple(T m):val(m) { } /* Simple<T>& operator= (Simple<T> const &b) { std::cout << "operator= " << "a:" << this << "b:" <<&b <<std::endl; val = b.val; } */ Simple& operator= (Simple const &b) { std::cout << "operator= " << "a:" << this << " b:" <<&b <<std::endl; val = b.val; } void debug() { std::cout << "value :" << val <<std::endl; } }; int main() { Simple<int> a(10); Simple<int> b(11); a = b; a.debug(); return 0; }
结果:
A:0x22fe40
B:0x22fe30
operator= a:0x22fe40 b:0x22fe30
value :11
如何修改函数对象的内容通过for_each()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <algorithm> #include <map> #include <cmath> using namespace std; template <typename T> class init_map { public: void operator()(const T &rh){ m[m.size()] = rh; } T operator[](const int i) { return (*(m.find(i))).second; } friend ostream& operator<<(ostream &os, init_map <T>&v) { for(auto iter=v.m.begin(); iter!= v.m.end();iter++) { cout << (*iter).second <<endl; } return os; } private: map<int ,T> m; }; int main() { float f[] = {1.1f ,2.1f, 3.1f, 4.1f, 5.1f, 6.1f, 7.1f, 8.1f ,9.1f}; int counts = floor(sizeof(f)/sizeof(float)); init_map <float> mv; // make a function that point to your init_map object auto func = [&mv](float v){ mv(v); }; for_each(f,f+counts,func); cout << mv; return 0; }
....