• 关于C++类型萃取



      最近在看《STL源码剖析》,关于C++类型萃取的问题看了几天,感觉还是有些疑惑。

      如果在C++中声明一个“以迭代器所指对象的类型”为类别,应当如何做。C++只支持sizeof(),并未支持typeof()!即便动用RTTI性质中的typeid(),获得的也只是型别名称,不能做变量声明只用。

      可以利用function template的参数推导(argument deducation)机制。

     1 template <class T>
    2 struct MyIter {
    3 typedef T value_type;
    4 T* ptr;
    5 MyIter(T* p=0) : ptr(p){}
    6 T& operator*() const {retrun *ptr;}
    7 //...
    8 };
    9
    10 template <class I>
    11 typename I::value_type
    12 func(I ite)
    13 { return *ite; }
    14
    15 //...
    16 MyIter<int> ite(new int(8));
    17 cout<< func(ite);

      以func()为对外接口,却把实际操作全部置于func_impl()之中,由于func_impl()是一个function template,一旦被调用,编译器会自动进行template参数推导。于是导出型别T,顺利解决问题。

      迭代器所指对象的型别,称为该迭代器的value type。如果value type用于函数的返回值,上面的方法也就行不通了,毕竟函数的"template参数推导机制"推而导之的只是参数,无法推导函数的返回值。

      如果采用内嵌型别,如下:

     1 template <class I, class T>
    2 void func_impl(I iter, T t)
    3 {
    4 T tmp;
    5 // ...
    6 };
    7
    8 template <class I>
    9 inline
    10 void func(I iter)
    11 {
    12 func_impl(iter, *iter);
    13 }
    14
    15 int main()
    16 {
    17 int i;
    18 func(&i);
    19 }

      func()的返回型别必须加上关键词typename,因为T是一个template参数,在它被编译器具现化之前,编译器对T一无所悉,换句话说,编译器此时并不知道MyIter<T>::value_type代表的是一个型别或是一个member function或是一个data member。关键词typename的用意在于告诉编译器这是一个型别,才能顺利通过编译。

      但并不是所有的迭代器都是class type。原生指针就不是,如果不是class type就无法为其定义内嵌性别。C++采用了template partialspecialization(偏特化)。class template专门用来"萃取"迭代器的特性,而value type正是迭代器的特性之一。

    1 template <class I>
    2 struct iterator_traits{
    3 typedef typename I::value_type value_type;
    4 };

      这个所谓的traits,其意义是,如果I定义有自己的value type,那么通过这个traits的作用,萃取出来的value_type就是I::value_type。换句话说,如果I定义有自己的value type,先前那个func()可以写成这样:

    1 template <class I>
    2 typename iterator_traits<I>::value_type
    3 func(I ite)
    4 { return *ite; }

      traits可以拥有特化版本,令iterator_traits拥有一个partial specialization如下:

    1 template <class T>
    2 struct iterator_traits<T*>{
    3 typedef T value_type;
    4 };

      于是,原生指针int*虽然不是一种class type,亦可以通过traits取其value type。traits所扮演的“特性萃取机”角色,萃取各个迭代器的特性。所谓的迭代器特性,指的是迭代器的相应型别(associated types)。

      而vector定义如下:

    1 template <class T, class Alloc = alloc>
    2 class vector {
    3 public:
    4 typedef T value_type;
    5 typedef value_type* iterator;
    6 ...
    7 }

      而使用了两个typedef是为了使其有意义,便于理解,而没有进行类型的萃取。萃取机制是从一个指针萃取出指针所指的型别,而在上述的定义中,是将一个型别取地址,并没有使用iterator_traits进行萃取。


      

  • 相关阅读:
    使用 dataset 管理数据(官网)
    Echarts-主题切换
    Echarts-数据的视觉映射
    【洛谷P3082】【USACO13MAR】—项链Necklace(Kmp+DP)
    【洛谷P3082】【USACO13MAR】—项链Necklace(Kmp+DP)
    【洛谷P3706】【SDOI2017】—硬币游戏(哈希+高斯消元)
    【洛谷P3706】【SDOI2017】—硬币游戏(哈希+高斯消元)
    【洛谷P3426】【POI2005】—SZA-Template(Kmp+链表)
    【洛谷P3426】【POI2005】—SZA-Template(Kmp+链表)
    【BZOJ4974】【Lydsy1708月赛】—字符串大师(Kmp)
  • 原文地址:https://www.cnblogs.com/yangbheb/p/2215069.html
Copyright © 2020-2023  润新知