1. 程式人生 > >C++ 模板中的型別獲取(一)

C++ 模板中的型別獲取(一)

C++ 模板中的型別獲取

1. 型別判斷

  • 嚴格型別比較:std::is_same<T1, T2>::value

    cout << std::is_same<int, int>::value << endl; // true
    cout << std::is_same<int, long>::value << endl; // false
    cout << std::is_same<int, unsigned int>::value << endl; // false
    cout << std:
    :is_same<int, const int>::value << endl; // false cout << std::is_same<int, int&>::value << endl; // false cout << std::is_same<int, int*>::value << endl; // false
  • 退化型別比較:std::decay<T>::type

    cout << std::is_same<int, std::decay<int>
    ::type>::value << endl; // ture cout << std::is_same<int, std::decay<long>::type>::value << endl; // false cout << std::is_same<int, std::decay<unsigned int>::type>::value << endl; // false cout << std::is_same<int, std::decay<const int>:
    :type>::value << endl; // true cout << std::is_same<int, std::decay<int&>::type>::value << endl; // ture cout << std::is_same<int, std::decay<int*>::type>::value << endl; // false

2. 容器元素型別

  • STL 的容器支援: Container::value_type

    using type = Container::value_type;

3. 迭代器型別

  • 標頭檔案:#include <type_traits>
  • using type = std::iterator_traits<Itr>::value

4. 函式返回型別

  • std::result_of<Func()>::type

5. 舉兩栗子

  • 判斷STL容器是否包含某元素:

    • 當容器元素為基本型別時:
    // map::value_type is const std::pair<const T, T>
    // need reload operator "==" to pass compile
    template <class T>
    bool operator==(const pair<const T,T> p1, const pair<T,T> p2){
        return p1.first==p2.first && p1.second==p2.second;
    }
    
    // basic value type
    template <class Container, class ItemType>
    int isContain(Container const &container, ItemType const &item){
        using type = typename std::decay<typename Container::value_type>::type;
        bool isSame = std::is_same<type, typename std::decay<ItemType>::type>::value;
        if(!isSame){
            cout << "error type not same " << endl;
            return -1;
        } else {
            int index=0;
            for(auto itr = container.begin();itr != container.end();){
                if(*itr == item){
                    break;
                } else {
                    itr++;
                    index++;
                }
            }
            return index;
        }
    };
    • 當元素型別為自定義的class或struct時:
    // user defined value type
    template <class Container, class ItemType>
    int isContain(Container const &container, ItemType const &item, bool func(ItemType const, ItemType const)){
        using type = typename std::decay<typename Container::value_type>::type;
        bool isSame = std::is_same<type, typename std::decay<ItemType>::type>::value;
        if(!isSame){
            cout << "error type not same " << endl;
            return -1;
        } else {
            int index=0;
            for(auto itr = container.begin();itr != container.end();){
                if(func(*itr, item)){
                    break;
                } else {
                    itr++;
                    index++;
                }
            }
            return index;
        }
    };
  • 對STL容器的元素求和:

    元素為基本型別時,用std::accumulate(container.begin(), container.end(), 0);即可,

    當元素為自定義的型別時:

    template <typename Container, typename ItemType>
    ItemType accumulate(Container container, ItemType getValue){
      ItemType sum;
      for (int i = 0; i < container.size(); ++i) {
          sum += getValue(container.at(i));
      }
      return sum;
    }
    struct Pt{
    int x;
    int y;
    }
    
    int getValue(Pt pt){ return pt.x;}
    
    int main(){
    vector<Pt> pts = {{1,2}, {2,3}, {3,4}};
    auto sum = accumulate(pts,getValue); // 執行OK
    return 0;
    }
    

    這樣寫模板函式,type ItemType 當作函式的返回型別, 傳入匿名(lambda) 函式時會報錯不能通過編譯
    mismatched types ... main()::<lambda(int)>
    例如:

    auto getValueX = [](Pt pt)->int{return pt.x;};
    auto sum = accumulate(pts,getValueX);

    或者:

    auto sum = accumulate(pts,[](Pt pt){return pt.x;});

    所以模板函式傳入的函式應該是函式指標型別, 返回型別用std::result_of獲取:

    template<typename Container, typename Func>
    auto add(Container& container, Func getValue) -> typename std::result_of<Func(typename Container::value_type)>::type {
      using type = typename std::result_of<Func(typename Container::value_type)>::type;
      type sum  = getValue(container.at(0));
      for (int i = 0; i < container.size(); ++i) {
          sum += getValue(container.at(i));
      }
      return sum;
    }