1. 程式人生 > >C++11中type_traits中的基石

C++11中type_traits中的基石

C++標準庫的的編寫方法是基於模板元來程式設計的,既然是用模板,那麼就少不了與型別打交道,而C++11標準庫中新加入了<type_traits>標頭檔案,這個裡面新加入了很多與型別特性有關的模板元,在編譯期間這些東西就是利器,非常好用。

而開啟<type_traits>標頭檔案,看到的第一個模板類就是integral_constant,這個類是type_traits的基石,基本上type_traits都直接或間接繼承自integral_constant,而且,C++標準庫中還有很多模板類也是繼承了integral_constant,例如std::ratio

integral_constant

的意思是積分常量,這是我Google 回來的意思,其實,這個類就是提供了一個編譯期常量。

先來看看原始碼:

/// integral_constant
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 { return value; } #if __cplusplus > 201103L #define __cpp_lib_integral_constant_callable 201304 constexpr value_type operator()() const { return value; } #endif }; template<typename _Tp, _Tp __v> constexpr _Tp integral_constant<
_Tp, __v>::value;

可以看到,integral_constant只有一個靜態常量表達式變數value,由於是靜態變數,因此要在類外宣告;

然後就是兩個typedef,這是traits的老套路了,喜歡在類中重定義一些型別,說白了就是把別人東西的包一層,然後作為一箇中間層告訴使用者需要的東西;

接著就是兩個操作符過載了。

在C++14中過載了函式運算子,這非常有用,假設現在你需要寫一個函式,這個函式返回App的版本號,這個版本號是個常量,不會變(假設啊),你肯定會這麼寫:

#define APP_VERSION 20181010L
const char * GetAppVersion() { return APP_VERSION; }

那麼在C++14中,你可以這麼寫:

struct GetAppVersion : public std::integral_constant<unsigned int, APP_VERSION> {};

然後像函式一樣呼叫就行了,auto appVersionString = GetAppVersion(),非常好用。因此,凡是需要返回一些常量的函式都可以這麼寫。

到這裡,原始碼就分析完了,是不是特別簡單,但是,這東西有什麼用呢?貌似還沒有說清楚。

先來看看三個特別重要的東西:

/// 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;

template<bool __v>
using __bool_constant = integral_constant<bool, __v>;

前兩個是不是好熟悉啊,看《STL原始碼剖析》,SGI有一個__type_traits也有__true_type__false_type,從前面的兩條下劃線可以知道,當時的__type_traits只能供內部使用,並不是C++標準規範之中的內容,然後再來看看當時的這兩個型別是如何定義的:

struct __true_type {};
struct __false_type {};

把這兩個定義和C++11中的兩個定義比較一下,你就會發現,C++11的true_type / false_type是多麼有血有肉,呼叫std::true_type::value還可以得到true

這也是為什麼我之前說type_traits中的大部分類都直接或間接繼承自integral_constant,你可以繼續看看type_traits中其他類,凡是帶字首is_*的類的偏特化特化都是繼承自true_type。例如下面的__is_pointer_helper

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

template<typename _Tp>
struct __is_pointer_helper<_Tp*> : public true_type { };

這種例子在type_traits中比比皆是。

__bool_constant這是一個輔助型別重定義,可以用在模板函式過載中。

integral_constant的另一作用就是用在std::ratio編譯器分數類中,這個在另一篇部落格會有介紹。

目前解除到的關於integral_constant就這麼多,以後有機會再完善。