更多 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