在modern c++中,模板元編程有哪些更方便的寫法?


對於不熟悉新標準的人來說,這是個好問題。C++11以來,Modern C++中對模板元編程是越來越重視的。Modern C++的模板元編程和以往的經典模板元編程(元數據,元函數,元函數類那一套)有很大的區別。這裡談一些自己的心得體會,權當拋磚引玉。


  • constexpr

constexpr是給模板元編程帶來最大影響的關鍵字。在沒有constexpr之前,求階乘我們只能用經典模板元編程那一套(熟悉C++的朋友一定很熟悉這段代碼):

template &
struct fact
{
static const int value = N * fact&::value;
};

template &<&>
struct fact&<0&>
{
static const int value = 1;
};

然而,有了constexpr之後,可以用模板函數來計算靜態值了:

template&
constexpr int fact()
{
return X * fact&();
}

template &<&>
constexpr int fact&<0&>()
{
return 1;
}

  • if constexpr

以往的模板函數的分支只能靠標籤分配:

template &
constexpr auto f()
{
return g(Is_Some_Type&::type());
}

constexpr auto g(True_Type)
{
//do something1;
}

constexpr auto g(Fale_Type)
{
//do something2;
}

if constexpr大大簡化了編譯期的分支流程編寫。if constexpr編譯期判決,執行其中一個分支,所以另一個分支即使有語義錯誤也沒關係。所以if constexpr基本上可以代替標籤分配(但是這個語句只能用在模板函數中,經典模板元編程用不上這個):

template &
constexpr auto f()
{
if constexpr(Is_Some_Type&::value)
{
//do something1;
}
else
{
//do something2;
}
}

  • fold

對於模板的可變參數列表,要想針對每一個類型進行處理,最後得到一個結果,以往的方法是遞歸:

template &
struct SumSquare
{
using type = SumSquare&;
static constexpr int value = (Arg * Arg) + (SumSquare&::value);
};

template &
struct SumSquare&
{
using type = SumSquare&;
static constexpr int value = Arg * Arg;
};

然而有了fold之後:

template &
struct SumSquare
{
using type = SumSquare&;
static constexpr int value = (... + (Args * Args));
};

  • typename

typename可以用作模板的模板參數了。以前的情況是只能用class聲明,很突兀:

template & struct Container {};

template &