Template metaprogram converting type to unique number

后端 未结 9 928
小鲜肉
小鲜肉 2020-12-03 03:37

I just started playing with metaprogramming and I am working on different tasks just to explore the domain. One of these was to generate a unique integer and map it to type,

相关标签:
9条回答
  • 2020-12-03 04:18

    Similiar to Michael Anderson's approach but this implementation is fully standards compliant and can be performed at compile time. Beginning with C++17 it looks like constexpr values will be allowed to be used as a template parameter for other template meta programming purposes. Also unique_id_type can be compared with ==, !=, >, <, etc. for sorting purposes.

    // the type used to uniquely identify a list of template types
    typedef void (*unique_id_type)();
    
    // each instantiation of this template has its own static dummy function. The
    // address of this function is used to uniquely identify the list of types
    template <typename... Arguments>
    struct IdGen {
       static constexpr inline unique_id_type get_unique_id()
       {
          return &IdGen::dummy;
       }
    
    private:
       static void dummy(){};
    };
    
    0 讨论(0)
  • 2020-12-03 04:21

    I don't think it's possible without assigning the numbers yourself or having a single file know about all the types. And even then you will run into trouble with template classes. Do you have to assign the number for each possible instantiation of the class?

    0 讨论(0)
  • 2020-12-03 04:21

    type2int as compile time constant is impossible even in C++11. Maybe some rich guy should promise a reward for the anwser? Until then I'm using the following solution, which is basically equal to Matthew Herrmann's:

    class type2intbase {
        template <typename T>
        friend struct type2int;
    
        static const int next() {
            static int id = 0; return id++;
        }
    };
    
    template <typename T>
    struct type2int {
        static const int value() {
            static const int id = type2intbase::next(); return id;
        }
    };
    

    Note also

    template <typename T>
    struct type2ptr {
        static const void* const value() {
            return typeid(T).name();
        }
    };
    
    0 讨论(0)
  • 2020-12-03 04:23

    This may be doing some "bad things" and probably violates the standard in some subtle ways... but thought I'd share anyway .. maybe some one else can sanitise it into something 100% legal? But it seems to work on my compiler.

    The logic is this .. construct a static member function for each type you're interested in and take its address. Then convert that address to an int. The bits that are a bit suspect are : 1) the function ptr to int conversion. and 2) I'm not sure the standard guarantees that the addresses of the static member functions will all correctly merge for uses in different compilation units.

    typedef void(*fnptr)(void);
    
    union converter
    {
      fnptr f;
      int i;
    };
    
    template<typename T>
    struct TypeInt
    {
      static void dummy() {}
      static int value() { converter c; c.f = dummy; return c.i; }
    };
    
    int main()
    {
      std::cout<< TypeInt<int>::value() << std::endl;
      std::cout<< TypeInt<unsigned int>::value() << std::endl;
      std::cout<< TypeInt< TypeVoidP<int> >::value() << std::endl;
    }
    
    0 讨论(0)
  • 2020-12-03 04:25

    This does what you want. Values are assigned on need. It takes advantage of the way statics in functions are assigned.

    inline size_t next_value()
    {
         static size_t id = 0;
         size_t result = id;
         ++id;
         return result;
    }
    
    /** Returns a small value which identifies the type.
        Multiple calls with the same type return the same value. */
    template <typename T>
    size_t get_unique_int()
    {
         static size_t id = next_value();
         return id;
    }
    

    It's not template metaprogramming on steroids but I count that as a good thing (believe me!)

    0 讨论(0)
  • 2020-12-03 04:26

    The closest I've come so far is being able to keep a list of types while tracking the distance back to the base (giving a unique value). Note the "position" here will be unique to your type if you track things correctly (see the main for the example)

    template <class Prev, class This>
    class TypeList
    {
    public:
       enum
       {
          position = (Prev::position) + 1,
       };
    };
    
    template <>
    class TypeList<void, void>
    {
    public:
      enum
      {
         position = 0,
      };
    };
    
    
    #include <iostream>
    
    int main()
    {
            typedef TypeList< void, void> base;  // base
            typedef TypeList< base, double> t2;  // position is unique id for double
            typedef TypeList< t2, char > t3; // position is unique id for char
    
            std::cout << "T1 Posn: " << base::position << std::endl;
            std::cout << "T2 Posn: " << t2::position << std::endl;
            std::cout << "T3 Posn: " << t3::position << std::endl;
    
    }
    

    This works, but naturally I'd like to not have to specify a "prev" type somehow. Preferably figuring out a way to track this automatically. Maybe I'll play with it some more to see if it's possible. Definitely an interesting/fun puzzle.

    0 讨论(0)
提交回复
热议问题