I want to be able to create switch statements over a type's ID. I've found a mechanism that could give a unique ID for different types. It's very simple:
template <typename T>
struct type { 
    static void id() { } 
};
template <typename T>
constexpr const size_t type_id() {
    return reinterpret_cast<size_t>(&type<T>::id); 
}
I thought this would evaluate to a constant that I could use as cases for the switch. But I get an error that the case expression is not a constant when I do the following:
int main(void) {
    size_t a = type_id<int>();
    switch (a) {
    case type_id<int>():
        break;
    }
    return 0;
}
Why is it not a constant? How could I achieve this effect?
Edit:
Can I do something like this without the reinterpret_cast then?
I'm not sure it's a good idea but... just for fun... using the constexpr counter, suggested in this page, you should be able to substitute the value of the pointer.
The following is a (I repeat: just for fun) full experiment
#include <iostream>
template <int N>
struct flag
 { friend constexpr int adl_flag (flag<N>); };
template <int N>
struct writer
 {
   friend constexpr int adl_flag (flag<N>)
    { return N; }
   static constexpr int value { N };
 };
template <int N, int = adl_flag (flag<N> {})>
int constexpr reader (int, flag<N>)
 { return N; }
template <int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1> {}))
 { return R; }
int constexpr reader (float, flag<0>)
 { return 0; }
template <int N = 1>
int constexpr next (int R = writer<reader (0, flag<32> {}) + N>::value)
 { return R; }
template <typename T>
struct type
 { 
   static constexpr int id { next() };
   constexpr static int type_id ()
    { return id; }
 };
void printType (int idT )
 {
   switch ( idT )
    {
      case type<int>::type_id():
         std::cout << "- int type" << std::endl;
         break;
      case type<long>::id:
         std::cout << "- long type" << std::endl;
         break;
      default:
         std::cout << "- another type" << std::endl;
         break;
    }
 }
int main ()
 {
   int ii { type<int>::id };
   int il { type<long>::type_id() };
   printType(ii);
   printType(il);
 }
                        I would like to suggest another approach which involves constexpr functions and macros (eeeewww...):
// Some naive text hashing function
template <std::size_t SIZE>
constexpr std::size_t hash(const char (&type_name)[SIZE])
{
    std::size_t result{0xf};
    for (const auto &c : type_name)
    {
        result <<= 1;
        result |= c;
    }
    return result;
}
First we create  a constexpr function able to transform a string literal into a number, this is my approach but you can choose anoter function as long as it is constexpr, then we create a macro which stringify the given parameter using the #:
#define TYPE_ID(X) hash(#X)
And now, we can use it:
int main(void) {
    size_t a = TYPE_ID(int);
    switch (a) {
    case TYPE_ID(int):
        break;
    }
    return 0;
}
Pros:
Cons:
TYPE_ID(I LOVE BACON) is valid.TYPE_ID(size_t) and TYPE_ID(unsigned long) even if they might be the same type.constexpr functions can not use reinterpret_cast in any shape or form. Some more formal reading can be found at http://en.cppreference.com/w/cpp/language/constant_expression 
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With