C++模版及其他

        先写点题外话。本来是想在本科阶段写点儿所谓的技术博客的,可惜最后没有实现。究其原因,不外乎懒散而已。现在也是时候付诸行动了,写点儿东西。随笔之类的东西我写了不少,博客我想还是尽量以学习技术为主吧,偶尔穿插点我个人的感悟和废话,呵呵。好了,闲聊到此结束,开始正题。
        读了研之后决定学学C++,因此这个系列很俗套地叫作“C++学习笔记”,今天的主要讨论对象是模版。 我对C++并没有完整的学习和研究,primer没有通读过,只是作为参考手册在遇到问题或感兴趣的章节时查阅一下,因此我的表述会有不严谨的地方,欢迎批评指正。
       模版大家应该都不陌生

template<typename T>

class A{};


        以上就是一个最简单的模版类。顺便说点细节问题:第一个细节是typename也可以换成class,并且更常用,但从含义上来说,typename更准确,因为模版参数可以为基本类型,而其不是class。typename还有另一个作用,即告诉编译器某个标识符是一个type,这在泛型和模版编程中很有用,因为在某些情况下,模版参数进行类型的动态绑定之前,编译器不能在静态编译时期识别某个标识符是否为一个类,比如T::value_type,那么,这是一个type,还是一个member function亦或者data member呢?T是一个type,但除此之外,我们对其一无所知,它的内部构造是透明的,编译器自然无法辨别,因此需要在之前加上typename关键字指明T::value_type为一个type,这样才能通过编译。
        第二个细节:将class换成struct也可以。大家可能认为struct只是一些数据的集合体,其实在C++里,struct可以很复杂,复杂到什么程度?在功能上与class没有区别。当然,这是目前我所掌握的信息,究竟有没有本质区别,我可不敢打保票。一个class和struct可能惟一的区别是默认访问和继承权限,class的成员默认权限是private,struct是public。我当然不是瞎说的,也查了些资料。在Lippman的《Inside the C++ Object Model(中译本)》中和stroustrup(C++之父)的《The C++ Programming Language(中译本)》中应该是这么说的。stroustrup在P208 10.2.8节中明确写道:一个struct也就是一个类,但其成员默认为公有的。事实上,在STL源码中,许多模版类是用struct声明的

template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
           typename _Pointer = _Tp*, typename _Reference = _Tp&>
    struct iterator
    {
      /// One of the @link iterator_tags tag.
      typedef _Category  iterator_category;
      /// The type "pointed to" by the iterator.
      typedef _Tp        value_type;
      /// Distance between iterators is represented as this type.
      typedef _Distance  difference_type;
      /// This type represents a pointer-to-value_type.
      typedef _Pointer   pointer;
      /// This type represents a reference-to-value_type.
      typedef _Reference reference;
    };

#if __cplusplus >= 201103L

_GLIBCXX_HAS_NESTED_TYPE(iterator_category)

  template<typename _Iterator,
    bool = __has_iterator_category<_Iterator>::value>
    struct __iterator_traits { };

  template<typename _Iterator>
    struct __iterator_traits<_Iterator, true>
    {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };

  template<typename _Iterator>
    struct iterator_traits
    : public __iterator_traits<_Iterator> { };
#else
  template<typename _Iterator>
    struct iterator_traits
    {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };
#endif

  /// Partial specialization for pointer types.
  template<typename _Tp>
    struct iterator_traits<_Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef _Tp*                        pointer;
      typedef _Tp&                        reference;
    };

  /// Partial specialization for const pointer types.
  template<typename _Tp>
    struct iterator_traits<const _Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef const _Tp*                  pointer;
      typedef const _Tp&                  reference;
    };

  /**
   *  This function is not a part of the C++ standard but is syntactic
   *  sugar for internal library use only.
  */
  template<typename _Iter>
    inline typename iterator_traits<_Iter>::iterator_category
    __iterator_category(const _Iter&)
    { return typename iterator_traits<_Iter>::iterator_category(); }

  //@}

  // If _Iterator has a base returns it otherwise _Iterator is returned
  // untouched
  template<typename _Iterator, bool _HasBase>
    struct _Iter_base
    {
      typedef _Iterator iterator_type;
      static iterator_type _S_base(_Iterator __it)
      { return __it; }
    };

  template<typename _Iterator>
    struct _Iter_base<_Iterator, true>
    {
      typedef typename _Iterator::iterator_type iterator_type;
      static iterator_type _S_base(_Iterator __it)
      { return __it.base(); }
    };

#if __cplusplus >= 201103L
  template<typename _InIter>
    using _RequireInputIter = typename
      enable_if<is_convertible<typename
  iterator_traits<_InIter>::iterator_category,
          input_iterator_tag>::value>::type;
#endif

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif /* _STL_ITERATOR_BASE_TYPES_H */


如上,是iterator与iterator_traits的定义,在bits/stl_iterator_base_types.h文件中,贴出来只是让大家参考,并不是说我掌握了哈哈。

        我的话是不是有点多啊,说到现在都没说到正题。。我也不会排版,估计很难看,以后再说吧。。。
        大家应该看到了,在iterator定义中,总是出现value_type一类的标识符,为什么呢?因为C++是静态类型语言,在声明和定义变量时需要明确指定变量的type,而为了实现泛型编程(Generic Programming),出现了模版(template)。

 

template<typename T>


       这样的声明可以使代码通过编译,但如何知道T究竟是什么类型呢?C++提供了模版推导机制,这里就不说了,篇幅有限。。。我所说的东西可以在侯捷的《STL源码剖析》里找到。语言提供的模版推导机制有局限性,需要进一步实现。一个iterator如何知道自己所指向对象(包括内置基本类型)的类型和性质呢,可以在其中用value_type等字段指明。而为了支持原生指针类型,又需要再加一层封装,就是iterator_traits。具体仍然可以参见上书,不是三两句话就能完事的,等我再学习学习,也许会另写一篇文章。

       好了,开始下一个讨论:C++类模版的特化。
       特化包括全特化( Full Specialization)和偏特化(Partial Specialization)。这两个名词的定义似乎不是那么严格,先不管吧。

#include <iostream>
using namespace std;


template<typename T, typename U>

class A{
	public:
		const static int a = 0;
};

template<typename U>

class A<int, U>{
	public:
		const static int a = 1;
};

template<>
class A<int, float>{
	public:
		const static int a = 2;
};


int main()
{
	
	cout << A<int, float>::a << endl;
	
	return 0;
}

 

        以上代码分别定义了一个模板类、一个偏特化版本、一个全特化版本。近似来说,全特化就是全部特化,即针对所有的模板参数进行特化,偏特化就是部分特化,即针对部分模板参数进行特化。代码打印的结果是2,所以调用的是全特化版本的类,还是近似地说,编译器会调用特化程度最高的类(这句话只是根据实验推断的,我并没有查阅相关理论依据)。这应该也是个比较容易理解、很自然的特性,就好像局部变量覆盖同名全局变量一样。至于函数模版,只能全特化,不能偏特化,我似乎记得在某本书上说不是因为无法实现,只是没有必要而已,偏特化的功能可以通过函数重载实现,网上也是这么说的~
        先暂时写到这,等有时间再修改或者再写一篇。希望能坚持下去,欢迎一起交流学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值