更多 C++ 慣用法/Int-To-Type
- 將整型常量在編譯時視為型別。
- 基於常量整型值實現靜態呼叫分派。
整型常量包裝器
C++ 中的函式過載是基於不同型別的,這阻止了編譯時整型常量參與函式過載解析。至少有兩種不同的機制可以基於整型常量執行靜態分派。第一種是 enable-if 慣用法,另一種是下面描述的 int-to-type 慣用法。
Andrei Alexandrescu 在 Dr. Dobb's Journal 中首次描述了一個簡單的模板,為該慣用法提供瞭解決方案。
template <int I>
struct Int2Type
{
enum { value = I };
};
上面的模板為用於例項化模板的不同整數值建立了不同的型別。例如,Int2Type<5> 與 Int2Type<10> 不同。此外,整型引數儲存在關聯的常量 value 中。由於每個整型常量都會產生不同的型別,因此這個簡單的模板可用於基於整型常量進行靜態分派,如下所示。
考慮一個 Array 類,它封裝了一個固定大小的陣列,與來自 TR1 的標準陣列類非常相似。事實上,我們的 Array 類是作為標準 TR1 陣列類的派生類實現的,唯一的區別是它有一個 sort 函式。
我們打算基於陣列的大小在編譯時分派排序函式,以實現一些效能最佳化。例如,對大小為零或一的陣列進行排序應該是無操作的。類似地,小於 50 大小的陣列應使用插入排序演算法進行排序,而更大的陣列應使用快速排序演算法進行排序,因為插入排序演算法在小型資料大小方面通常比快速排序演算法更有效率。請注意,這種排序演算法的選擇可以透過執行時 if 條件輕鬆完成。但是,int-to-type 慣用法用於在編譯時實現相同的效果,如下所示。
#include <iostream>
#include <array>
template <int I>
struct Int2Type
{
enum { value = I };
};
template <class T, unsigned int N>
class Array : public std::array <T, N>
{
enum AlgoType { NOOP, INSERTION_SORT, QUICK_SORT };
static const int algo = (N==0) ? NOOP :
(N==1) ? NOOP :
(N<50) ? INSERTION_SORT : QUICK_SORT;
void sort (Int2Type<NOOP>) { std::cout << "NOOP\n"; }
void sort (Int2Type<INSERTION_SORT>) { std::cout << "INSERTION_SORT\n"; }
void sort (Int2Type<QUICK_SORT>) { std::cout << "QUICK_SORT\n"; }
public:
void sort()
{
sort (Int2Type<algo>());
}
};
int main(void)
{
Array<int, 1> a;
a.sort(); // No-op!
Array<int, 400> b;
b.sort(); // Quick sort
}
可以使用 Int2Type 模板定義更多關聯的型別和常量以提高其可用性。例如,列舉 value 用於檢索與型別關聯的整型常量。最後,其他型別定義,例如 next 和 previous,用於按順序查詢其他型別,這樣 Int2Type<7>::next 與 Int2Type<9>::previous 具有相同的型別。
template <int I>
struct Int2Type
{
enum { value = I };
typedef int value_type;
typedef Int2Type<I> type;
typedef Int2Type<I+1> next;
typedef Int2Type<I-1> previous;
};
- Boost.MPL 中的整型常量包裝器 (bool_, int_, long_)
- 量綱分析
- std::integral_constant
[1] Generic<Programming>: Mappings between Types and Values -- Andrei Alexandrescu