AlgebraMaster

Modern C++ 创造非凡 . 改变世界

导航

Templates<2>

 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*>("67");
    CastAndPrint<char,const char*>("67");
    return 0;
}
View Code

 

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[]{1,2,3,4,5};
    cout << accum(val,val+5) <<endl;

    char val2[] = "AA";
    cout << accum(val2,val2+3) <<endl; //130

    return 0;
}
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 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
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 += 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;
}
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 0;
}
View Code

(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[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;
}
View Code

 具体(SFINAE)解释程序:

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

 

 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=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;
}
main.cpp

 

 Metaprogram:

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

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

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

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

 不过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-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;
}
View Code

(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-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;
}
View Code

 

表达式模版:

 一个疑问点:一个简单的模版类:

 下面两种方案都一样:  

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

 

结果:

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 0;
}
View Code

 

 

....

posted on 2016-07-05 15:27  gearslogy  阅读(310)  评论(0编辑  收藏  举报