Search code examples
c++c++11templatesuniqueconstexpr

C++ constexpr values for types


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?


Solution

  • 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);
     }