《C++ Primer Plus 6th.ed》讀書筆記之四:簡單的type_traits實現及其應用

關於<type_traits>

<type_traits>是C++自2011年標準後添加到STL中的一個頭文件,正如其名,它提供了一系列模板類去確定類型的屬性,例如:

// 檢查傳入類型參數是否爲void
template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };

// 可以這樣使用它
#include <type_traits>
bool _v_flag = std::is_void<int>::value;  	// false
bool _i_flag = std::is_void<void>::value;	// true

更多具體示例見這裏,本文以is_void<>爲例,簡單剖析一下<type_traits>對c++內建類型的實現方法
那麼爲什麼不講一下對自定義類型的實現呢?因爲C++在編譯時無法產生太多的元信息,因此無法進行模板替換與展開,這部分代碼實現是直接寫在編譯器源碼中的,而我又比較懶,不想去翻gcc的源碼……

is_void<>模板展開

首先,is_void<>是一個模板類,只不過這個模板類是由struct定義的——除了成員訪問權限默認爲public,與class並無二致——它的源碼在文章開頭已經貼過了,這裏再貼一遍:

template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };

可以看到,它以公開繼承的方式繼承了另外一個模板類__is_void_helper,看來這個類模板是我們下一步要找的目標,不過先看一下這個繼承中的其他部分再去考慮這個基類的實現
其中remove_cv也是聲明在該文件中一個類模板,但是在該文件中僅有聲明而無實現,估計也是由編譯器實現的吧,它的作用是抹去傳入類型的const/volatile屬性,例如傳入類型參數爲const void,那麼其類型成員type將被指定爲void,這樣被繼承的基類部分就變成了__is_void_helper<void>::type
下面來看__is_void_helper<>的實現:

template<typename>
struct __is_void_helper : public false_type { };

template<>
struct __is_void_helper<void> : public true_type { }

這裏可以看到,根據傳入類型的不同,__is_void_helper<>具有兩條不同的繼承路線——傳入void就繼承true_type,否則繼承false_type,那麼下面繼續看這兩個不同基類的實現:

/// The type used as a compile-time boolean with true value.
typedef integral_constant<bool, true>     true_type;

/// The type used as a compile-time boolean with false value.
typedef integral_constant<bool, false>    false_type;

顯然這兩個基類是對同一個類型不同參數的類型重定義,那麼找到這個intergral_constant<typename _Tp, _Tp __v>至關重要:

template<typename _Tp, _Tp __v>
struct integral_constant
{
	static constexpr _Tp                  value = __v;
	typedef _Tp                           value_type;
	typedef integral_constant<_Tp, __v>   type;
	constexpr operator value_type() const noexcept { return value; }
}

這個時候就一目瞭然了,根據is_void<>傳入的類型參數不同,最後繼承的integral_constant也不同,整個模板的展開過程大致如下圖所示:

void
non-void
is_void<>
__is_void_helper< void >
__is_void_helper< typename T >
integral_constant< bool, true >
is_void< void >::value = true
integral_constant< bool, false >
is_void< void >::value = false

新標準中的<type_traits>

在C++14/17中,對該頭文件進行了多處修改,其中比較重要的有兩處:

  1. C++14中,對integral_constant模板添加了operator()的重載:

    constexpr value_type operator() const noexcept { return value; }
    

    這意味着可以將該模板作爲函數對象(functional object)傳遞,也可以用這樣的方式獲取類型判斷的結果:

    bool _v_flag = std::is_void<void>(); // true
    
  2. C++17中,添加了一種直接獲取integral_constant::value的模板變量,它具有這樣的通用命名方式is_type_v<>
    針對上例,可以這樣獲取類型判斷的結果:

    bool _v_flag = std::is_void_v<void>; // true
    

    但是要注意,在目前主流編譯器(GCC/MSVC)中默認使用的C++標準似乎是C++14從而導致編譯失敗,針對GCC可以在編譯命令中添加--std=c++17或者--std=c++2a解決這個問題

發佈了17 篇原創文章 · 獲贊 20 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章