1. 程式人生 > >c++ 型別萃取

c++ 型別萃取

型別萃取

型別萃取是基於c++中的模板特化來實現的,是對於模板特化的應用。
關於c++的模板特化

當我們寫一個同用的拷貝函式時,我們可以使用mymcpy進行拷貝,但是mymcpy是一個淺拷貝,對於一些基本型別的拷貝效率很高。但是對於要深拷貝的型別來說就不適用了,對於深拷貝我們可以使用for迴圈的方式來進行。
所以將兩者進行結合,當基本型別進行拷貝時使用mymcpy,當自定義型別進行拷貝時使用for迴圈的方式。

使用函式的方式進行實現

#include <iostream>
#include <cstring>
#include <typeinfo>
#include <string>
using namespace std;
/*
 *使用函式進行通用拷貝的實現,但時在基本型別的確定時需要迴圈,仍然造成一些效率問題 
 * 
 * 
 */
template<class T>
bool IsBasicType(const T* Type){

  const char* type_arr[] = { "int" , "char" , "float" , "double" , "long" , "short" , "long long" };  //這裡僅列舉了部分的基本型別
  for(int i = 0 ; i < sizeof(type_arr)/sizeof(type_arr[0]); ++i)
  {

    if(strcmp(type_arr[i] , Type) == 0)
      return true;
    return false;
  }

}


template<class T>
void Copy(T* dest , T* src, size_t size){

  if(IsBasicType(typeid(T).name()))
    memcpy(dest,src,size*sizeof(T));
  else{
  for(int i = 0; i < size; i++)
    {
      dest[i] = src[i];
    }
  }
}

int main()
{
//  string s1[] = {"www" , "eee" , "rrr"};
 // string s2[3];

  float s1[] = {11.1,33.2,33.4};
  float s2[3];
  Copy<float>(s2,s1,3);
  for(int i = 0; i < sizeof(s2)/sizeof(s2[0]); ++i)
     cout << s2[i] << endl; 
  return 0;
}

以上的函式雖然可以區分基本型別和自定義型別,但是在判斷是否為自定義型別時需要,迴圈並且需要strcmp進行字串比較,所以效率較大。

如果我們要想讓函式能夠自動識別是基本型別還是自定義的型別,這時我們就需要用到型別萃取了。

型別萃取實質上就是對於模板特化的應用,通過將基本型別每個都特化一次,在識別時就可以直接確定出所傳入的引數的型別。
  • 在對基本型別特化時,必需要將所有的型別都特化一變,包括有符號和無符號的型別
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
/*使用型別萃取
 *使用模板的特化,將所有的模板進行特化,使其能夠自動識別,從而少了之前
 * 迴圈判斷型別
 */

//先定義兩個型別的類,其中包含一個靜態的方法用於返回判斷條件所需的真假

//標識基本型別
struct BasicType{
  
  static bool Get(){
    return true;
  }

};

//標識自定義型別
struct DefineType{
  static bool Get(){
    return false;
  }
};

/*建立一個模板類用於識別是基本型別還是自定義型別
由於基本型別都被特化了,所以呼叫基礎模板函式的就是自定義型別

使用一個IsBsicType 來進行型別的重定義,以便呼叫Get()
*/
template<class T>
struct Type_recog{
  typedef DefineType IsBasicType;
};
//這裡只列舉了部分的基本型別
template<>
struct Type_recog<int>{
  typedef BasicType IsBasicType;
};


template<>
struct Type_recog<char>{
  typedef BasicType IsBasicType;
};

template<>
struct Type_recog<short>{
  typedef BasicType IsBasicType;
};

template<>
struct Type_recog<float>{
  typedef BasicType IsBasicType;
};

template<>
struct Type_recog<double>{
  typedef BasicType IsBasicType;
};

template<>
struct Type_recog<long>{
  typedef BasicType IsBasicType;
};

template<>
struct Type_recog<long long>{
  typedef BasicType IsBasicType;
};

template<class T>
void Copy(T* dest, T* src ,size_t size){
  if(Type_recog<T>::IsBasicType::Get())  
    memcpy(dest,src,size*sizeof(T));
  else {
    for(int i = 0; i < size; i++)
      dest[i] = src[i];
  }
}


int main(){
//  string s1[] = {"www","eee","rrr"};
//  string s2[3];

  int s1[] = {1,2,3};
  int s2[3];
  Copy<int>(s2,s1,3);
  for(int i = 0; i < sizeof(s2)/sizeof(s2[0]); ++i)
    cout << s2[i] << endl;
  return 0;
}