摘要訊息 : C++ 14 Proposal N3651《Variable Templates》導讀
程式設計師都是懶惰的人, 否則電腦將毫無用處. 在 C++ 11 中, 如果我們想要獲得某個特性萃取的結果, 我們通常會有這樣的程式碼 :
constexpr auto value {is_signed<int>::value};
對於某個固定的常數, 我們只能寫出這樣的程式碼 :
constexpr auto value {0};
如果在編寫程式的時候, 我們並不知道變數的型別, 那麼我們會寫一個函式 :
template <typename T>
T value() {
return 0;
}
而這篇 Proposal 提出了為 C++ 增加變數樣板. 變數樣板的基本形式是變數和函式樣板的中間體 :
template <樣板參數>
[constexpr] [static] [inline] T VARIABLE_NAME {初始化列表};
其中, 帶有 "[]" 的都是可選的, T
表示變數的型別
例如, \pi\doteq 3.1415926, 但是 3.1415926 這一常數在 C++ 中, 如果沒有任何後綴, 那麼預設是 double
型別. 而實際使用的時候, 它並不一定是 double
型別, 它可以是 long double
, 可以是 float
, 甚至可以是用戶自訂型別. 如果沒有辦法確定它的型別, 但是又要用到它, 那麼這篇 Proposal 提出的變數樣板的寫法將會非常簡便 :
template <typename T>
constexpr T pi {3.1415926};
回到我們最初的問題, 我們希望簡化陳述式 constexpr auto value {is_signed<int>::value};
運用變數樣板, 可以將其寫成 :
#include <type_traits>
using namespace std;
template <typename T>
constexpr auto is_signed_value {is_signed<T>::value};
那麼接下來, 我們就無需再使用 is_signed<T>::value
這樣的使用方式, 直接使用 is_signed_value<T>
即可. 是不是寫少了一些呢?
對於類別內的 static
變數, 同樣也可以使用樣板變數. 但是如果初始化在類別可視範圍之外, 那麼需要重新宣告樣板參數. 另外, 如果變數型別和樣板參數無關, 也就是變數的型別已知, 那麼變數必須在類別可視範圍內進行初始化 :
#include <iostream>
using namespace std;
struct Foo {
template <typename T>
static const volatile T value;
};
template <typename T>
const volatile T Foo::value {};
struct Bar {
template <typename T>
constexpr static bool value; //Error!
template <typename T>
constexpr static bool value {is_union<T>::value}; //OK
};
另外, 如果你熟悉 SFNIAE, 那麼需要注意的是, SFINAE 並不能用於變數樣板中 :
#include <iostream>
using namespace std;
template <int N>
typename enable_if<N % 2 == 0, int>::type value {};
int main(int argc, char *argv[]) {
cout << value<0> << endl; //輸出結果 : 0
cout << value<1> << endl; //Error : failed requirement '1 % 2 == 0'; 'enable_if' cannot be used to disable this
declaration
}
一旦編碼器檢測到 enable_if
的第一個樣板引數的結果為 false
, 那麼就會立馬擲出編碼錯誤. 另外, 宣告兩個帶有 SFINAE 的 value
看似可行, 但是這會導致編碼錯誤 :
template <int N>
typename enable_if<N % 2 == 0, int>::type value {};
template <int N>
typename enable_if<N % 2 == 1, char>::type value {'0'}; //redefinition of 'value' with a different type: 'typename enable_if<N % 2 == 1, char>::type' vs 'typename enable_if<N % 2 == 0, int>::type'
因此, SFINAE 並不可以被用於樣板參數 (其實, 讓變數樣板支援 SFINAE 的可行性已經被討論過了, 不過到 C++ 2a 為止, 它並沒有被採納)
自創文章, 原著 : Jonny, 如若需要轉發, 在已經授權的情況下請註明出處 :《【C++ 14 Proposal 導讀】變數樣板》https://jonny.vip/2020/01/17/%e3%80%90cplusplus-14-proposal-%e5%b0%8e%e8%ae%80%e3%80%91%e8%ae%8a%e6%95%b8%e6%a8%a3%e6%9d%bf/
Leave a Reply