STL中的check

很早之前,忘了是看書還是別人介紹了,說STL裏有一些類型檢查的東西,比如vector裏面會檢查是否定義了賦值操作符,還有的檢查是否有默認參數的構造函數之類的。看STL源碼的時候發現了一個concept_check的頭文件,發現其中的內容還真是不少。有一些就是做這種檢查的。

STL默認提供了很多種操作的檢查,比如:

_Allocator
_Assignable
_DefaultConstructible
_EqualityComparable
_LessThanComparable
_TrivialIterator
_InputIterator
_OutputIterator
_ForwardIterator
_BidirectionalIterator
_RandomAccessIterator
_Mutable_TrivialIterator
_Mutable_ForwardIterator
_Mutable_BidirectionalIterator
_Mutable_RandomAccessIterator

現在來看看是怎麼實現的。

舉個例子,一個C++的類TesetClass,如果我沒有重寫operator=,默認是由編譯器提供一個。而如果我寫了這個函數,但是沒有實現,並且把它寫爲private,這也算是一個常用的手法。這種情況下,如何去檢查出來?很簡單,如果我們定義它的一個對象a1,再定義一個對象a2,如果調用a1=a2,編譯器就會報錯,提示我們賦值操作符爲私有,沒有實現。很好,STL中也是採用類似的方式。來看下它是怎麼做的。

在此,也以賦值操作符爲例。

在vector中可以看到如下的一句代碼:

__STL_CLASS_REQUIRES(_Tp, _Assignable);
找到宏定義:

#define __STL_CLASS_REQUIRES(__type_var, __concept) \
  typedef void (* __func##__type_var##__concept)( __type_var ); \
  template <__func##__type_var##__concept _Tp1> \
  struct __dummy_struct_##__type_var##__concept { }; \
  static __dummy_struct_##__type_var##__concept< \
    __concept##_concept_specification< \
      __type_var>::__concept##_requirement_violation>  \
  __dummy_ptr_##__type_var##__concept
分析一下,typedef void (* __func##__type_var##__concept)( __type_var ); 定義了一個函數指針,參數是__type_var。

 template <__func##__type_var##__concept _Tp1> 
  struct __dummy_struct_##__type_var##__concept { }; 
上面兩句定義了一個模板類,不要小看它,可是大有作爲的。它的模板參數呢,就是上面定義的函數指針
static __dummy_struct_##__type_var##__concept< \
    __concept##_concept_specification< \
      __type_var>::__concept##_requirement_violation>  \
  __dummy_ptr_##__type_var##__concept
定義了前面提到的模板類的一個對象。這個模板對象的模板實參呢,就是下面即將提到的,STL定義好的函數,而這個函數就是用於檢查賦值操作符的。這句中__concept##_concept_specification< __type_var>::__concept##_requirement_violation整體是模板實參,也就是一個函數指針,而這個模板實參又是用的一個模板。__concept##_requirement_violation函數,是模板類__concept##_concept_specification< __type_var>的一個函數。下面我們繼續上代碼,現在越來越清晰了。

代入_Assignable,來看下。

template <class _Type>
struct _Assignable_concept_specification {
  static void _Assignable_requirement_violation(_Type __a) {
    _STL_ERROR::__assignment_operator_requirement_violation(__a);
    _STL_ERROR::__copy_constructor_requirement_violation(__a);
    _STL_ERROR::__const_parameter_required_for_copy_constructor(__a,__a);
    _STL_ERROR::__const_parameter_required_for_assignment_operator(__a,__a);
  }
};
模板類_Assignable_concept_specification其實就是上面的__concept##_concept_specification< __type_var>,它的函數_Assignable_requirement_violation其實就是__concept##_requirement_violation了。現在都已經清楚了。但是具體內容還沒有,彆着急,謎底馬上揭曉。

struct _STL_ERROR {
template <class _Type>
  static _Type
  __assignment_operator_requirement_violation(_Type __a) {
    __a = __a;
    return __a;
  }
}
這裏就值給出了一個函數的實現,不過已經能夠充分說明問題了。這個函數調用了賦值操作!還記得我們是怎麼判斷賦值操作的吧,就是這樣子,是不是很簡單?

一個靜態模板對象傳遞一個模板類型的函數,這個函數調用會檢查賦值操作,當然不止是賦值操作,文章最開始提到的幾種操作都包含。

不過得說一下一個令人沮喪的結果,我在vc2010中採用如是方式進行驗證,發現編譯器並不會報錯,然而使用g++編譯時則會報錯。看來不同的編譯器是做了不同的處理的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章