Templates<2>

时间:2022-11-18 06:33:13

Part:template specialized

Part1:template specialized

#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*>("");
CastAndPrint<char,const char*>("");
return ;
}

part2:Trait & Policy

(1) accumulation,可能的累积定义

//
// 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

accumtraits.h

#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

accum2.h

#include <iostream>
#include "accum2.h"
using namespace std;
int main()
{ int val[]{,,,,};
cout << accum(val,val+) <<endl; char val2[] = "AA";
cout << accum(val2,val2+) <<endl; // return ;
}

main.cpp

 (2) Trait 和 Policy为我们的程序提供一个用户可以编辑的模版接口

accumlation.h把所有的定义都写了

//
// 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 ;}
}; template <>
class AccumulationTraits<int>
{
public:
typedef int AccT;
static AccT zero() { return ;}
}; template <>
class AccumulationTraits<short>
{
public:
typedef int AccT;
static AccT zero() { return ;}
}; template <>
class AccumulationTraits<unsigned int>
{
public:
typedef unsigned long AccT;
static AccT zero() { return ;}
}; 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

accumlation.h

main.cpp提供了2个新Policy接口,但是我们的乘法接口会出现问题,因为初值zero()

#include <iostream>
#include "accumulation.h" //
class DoubleAddPolicy
{
public:
template <typename T1,typename T2>
static void accumulate(T1 &total , T2 const &value)
{
total += * 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[]{,,,,,};
cout << Accum<int>::accum(val,val+) <<endl; char cval[] = "AA";
cout << Accum<char>::accum(cval,cval+)<<endl; float fval[]{1.0,2.0,3.0,4.0,5.0};
cout << Accum<float>::accum(fval,fval+)<<endl; cout << Accum<float,DoubleAddPolicy>::accum(fval,fval+) <<endl; // but next result will is zero,because our value initialized to zero
cout << Accum<float,MultPolicy>::accum(fval,fval+) <<endl;
return ;
}

main.cpp

Part3:Type function

(1) 确定容器元素类型

#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 ;
}

(2) Why the container::value_type is import?

检查一个类型是类,还是不是类(SFINAE,substitution-failure-is-not-error,替换失败并非错误):

#include <iostream>

template <typename T>
class IsClassT
{
private:
typedef struct {char a[];} char2;
template <typename C>
static char test(int C::*); template <typename C>
static char2 test(...); public:
enum{Yes=sizeof(IsClassT<T>::test<T>()) == };
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 ;
}

具体(SFINAE)解释程序:

#include <iostream>
using namespace std; typedef struct char2
{
char a[];
}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; //
std::cout <<sizeof(char2) <<endl; // std::cout << sizeof(test<int>()) << endl; // 2,select test(...) function
std::cout << sizeof(test<Value>()) << endl; // 1,select test(int T::*) function return ;
}

Promotion trait:

#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

ifthenelse.hpp

#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

promote.hpp

#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=;i<val1.size();i++)
{
result.push_back(val1[i] + val2[i]);
}
return result;
}; int main()
{
std::cout <<add(,2.0f)<< std::endl;
vector<int> val_01();
fill(val_01.begin(),val_01.end(),);
vector<float> val_02();
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 ;
}

main.cpp

Metaprogram:

<1>计算一个数的n次方

#include <iostream>

template <int S,int N>
class pow
{
public:
enum {result = S*pow<S,N->::result};
}; template <int S>
class pow<S,>
{
public:
enum{result = };
}; template <int N>
class pow<,N>
{
public:
enum{result};
}; template <>
class pow<,>
{
public:
enum{ result};
}; int main()
{
std::cout << pow<,>::result <<std::endl; // 3^2
std::cout << pow<,>::result <<std::endl; // 2^2
return ;
}

上面的代码依然可以用static int const result 代替:

#include <iostream>

template <int S,int N>
class pow
{
public:
static const int result = S*pow<S,N->::result;
}; template <int S>
class pow<S,>
{
public:
static const int result = ;
}; template <int N>
class pow<,N>
{
public:
static const int result = ;
}; template <>
class pow<,>
{
public:
static const int result = ;
}; int main()
{
std::cout << pow<,>::result <<std::endl; // 3^2
std::cout << pow<,>::result <<std::endl; // 2^2
return ;
}

不过static int 出来的数据永远是个左值。

<2>For循环展开:

(1)图形学dot()函数

#include <iostream>
template <int DIM, typename T>
class DotProduct
{
public:
static T result(T *a,T *b)
{
return (*a) * (*b) + DotProduct<DIM-,T>::result(a+,b+);
}
};
template <typename T>
class DotProduct<,T>
{
public:
static T result(T *a,T*b)
{
return (*a) * (*b);
}
}; int main() {
float a[] = {,,};
float b[] = {,,};
std::cout << DotProduct<,float>::result(a,b) << std::endl;
return ;
}

(2)求数组合和数组乘积Accumulate

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-,T,Type>::result(data+);
return *data * Accumulate<N-,T,Type>::result(data+);
}
}; template <typename T,Accumulate_Type Type>
class Accumulate<,T,Type>
{
public:
static T result(T *data)
{
return *data;
}
}; void testAccumulate()
{
float a[] = {,,};
std::cout << "Mutiply:"<<Accumulate<,float,Accumulate_Type::Mutiply>::result(a)<<std::endl;
std::cout << "Add:" <<Accumulate<,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;
}

类定义全部定义:

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();
Simple<int> b();
a = b;
a.debug();
return ;
}

结果:

A:0x22fe40
B:0x22fe30
operator= a:0x22fe40 b:0x22fe30
value :11

如何修改函数对象的内容通过for_each()

#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 ;
}

....