1. 程式人生 > 其它 >C++中的模板超程式設計

C++中的模板超程式設計

開個新坑,一堆破模板玩意 目錄

概述

模板超程式設計可以說是C++中最困難也是最強大的程式設計正規化。模版超程式設計不同於普通的執行期程式,它執行完全是在編譯期,並且它操縱的資料不能是執行時變數,只能是編譯期常量(且不可修改)。因此,模版超程式設計需要很多技巧,在這裡你會遇到非常多的列舉常量、繼承、模板偏特化、可變模板引數、型別萃取等方法,如果要讀懂STL庫,那麼模板超程式設計必須要掌握;不僅如此,C++中的許多黑科技都是依賴於模板超程式設計的,例如我們甚至可以寫出編譯期排序的演算法

模板超程式設計:template meta programing

前置知識

模板超程式設計又兩個部分組成:元資料和元函式。元資料是指編譯期能在編譯期處理的資料,即編譯期常量;元函式指操縱元資料的函式,在編譯期呼叫,它通常表現為一個模板類或一個模板函式

模板超程式設計十分特殊,它無法使用if-elseforwhile這些執行期語句,在模板超程式設計中,我們時常會使用到這些語法:

  • enum,static-constexpr:用來定義編譯期的整數常量
  • usingtypedef:定義元資料
  • T,Ts...:用來宣告元資料型別
  • template:定義元函式
  • :::用來解析型別作用域獲取元資料

constexpr

type_traits

<type_traits>是C++11提供的模板元基礎庫,它提供了模板超程式設計中需要的常用的基礎元函式

std::integral_constant,定義編譯期常量

舉個例子,C++11中提供了std::integral_constant來定義編譯期常量

template<typename T>
using one_constant = std::integral_constant<T, 1>;

template<typename T>
struct one_struct : std::integral_constant<T, 1> {};

因此我們可以使用one_constant<int>::valueone_struct<int>::value來獲取編譯期常量int 1

而在C++11之前,我們定義這個常量就需要用到enum或static-const

struct one_struct
{
    enum { value = 1 };
};
struct one_struct
{
    static const int value = 1;  
};

然後通過one_struct::value來訪問值,其中enum能隱式轉換為int

std::integral_constant的實現也非常的簡單

template <class _Ty, _Ty _Val>
struct integral_constant {
    static constexpr _Ty value = _Val;

    using value_type = _Ty;
    using type       = integral_constant;

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

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

可以看到,通過C++11的<type_traits>提供的一個簡單的std::integral_constant就可以很方便的定義編譯期常量,而無需再去使用enum和static-const。緊接著,庫中又提供了編譯期常量的bool型別

using true_type  = bool_constant<true>;
using false_type = bool_constant<false>;

std::integer_sequence,定義編譯期整數序列

為什麼說是整形呢,請看原始碼

// 一個型別加上一個非型別模板引數包
template <class _Ty, _Ty... _Vals>
struct integer_sequence { // sequence of integer parameters
    static_assert(is_integral_v<_Ty>, "integer_sequence<T, I...> requires T to be an integral type.");

    using value_type = _Ty;

    _NODISCARD static constexpr size_t size() noexcept {
        return sizeof...(_Vals);
    }
};