# Int-To-TypeEdit

### IntentEdit

- To treat an integral constant as a type at compile-time.
- To achieve static call dispatch based on constant integral values.

### Also Known AsEdit

Integral constant wrappers

### MotivationEdit

Function overloading in C++ is based on different types, which prevents compile-time integral constants taking part into function overload resolution. There are at least two different mechanisms to perform static dispatching based on integral constants. First is enable-if idiom and the other one is the int-to-type idiom described below.

### Solution and Sample CodeEdit

A simple template, initially described in Dr. Dobb's Journal by Andrei Alexandrescu provides a solution to this idiom.

template <int I> struct Int2Type { enum { value = I }; };

The above template creates different types for different integer values used to instantiate the template. For example, *Int2Type<5>* is a different type from *Int2Type<10>*. Moreover, the integral parameter is saved in the associated constant *value*. As each integral constant results in a different type, this simple template can be used for static dispatching based on integral constants as shown below.

Consider an *Array* class that encapsulates a fixed size array very similar to that of the standard array class from TR1. In fact, our Array class is implemented as a derived class of the standard TR1 array class with the only difference of a *sort* function.

We intend to dispatch sort function at compile-time based on the size of the array to achieve some performance optimizations. For example, sorting an array of size zero or one should be a no-op. Similarly, arrays smaller than size 50 should be sorted using the insertion-sort algorithm whereas as larger arrays should be sorted using the quick-sort algorithm because insertion-sort algorithm is often more efficient than quick-sort algorithm for small data size. Note that, this selection of the sorting algorithm can be trivially done using run-time *if* condition. However, int-to-type idiom is used to achieve the same effect at compile-time as shown below.

#include <iostream> #include <tr1/array> template <int I> struct Int2Type { enum { value = I }; }; template <class T, unsigned int N> class Array : public std::tr1::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 }

Few more associated types and constants can be defined with *Int2Type* template to increase its usability. For example, enumeration *value* is used to retrieve the integer constant associated with the type. Finally, other typedefs such as, *next* and *previous* are used to find other types *in order* such that *Int2Type<7>::next* is the same type as *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; };

### Known UsesEdit

### Related IdiomsEdit

### ReferencesEdit

[1] Generic<Programming>: Mappings between Types and Values -- Andrei Alexandrescu