Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template metaprogram converting type to unique number

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, like below:

int myInt = TypeInt<AClass>::value;

Where value should be a compile time constant, which in turn may be used further in meta programs.

I want to know if this is at all possible, and in that case how. Because although I have learned much about exploring this subject I still have failed to come up with an answer.

(P.S. A yes/no answer is much more gratifying than a c++ solution that doesn't use metaprogramming, as this is the domain that I am exploring)

like image 283
daramarak Avatar asked Nov 10 '09 14:11

daramarak


3 Answers

In principle, this is possible, although the solution probably isn't what you're looking for.

In short, you need to provide an explicit mapping from the types to the integer values, with one entry for each possible type:

template< typename T >
struct type2int
{
   // enum { result = 0 }; // do this if you want a fallback value
};

template<> struct type2int<AClass> { enum { result = 1 }; };
template<> struct type2int<BClass> { enum { result = 2 }; };
template<> struct type2int<CClass> { enum { result = 3 }; };

const int i = type2int<T>::result;

If you don't supply the fallback implementation in the base template, this will fail for unknown types if T, otherwise it would return the fallback value.

Depending on your context, there might be other possibilities, too. For example, you could define those numbers within within the types themselves:

class AClass {
  public:
    enum { inta_val = 1 };
  // ...
};

class BClass {
  public:
    enum { inta_val = 2 };
  // ...
};

// ... 

template< typename T >
struct type2int
{
   enum { result = T::int_val }; // will fail for types without int_val
};

If you give more context, there might be other solutions, too.

Edit:

Actually there isn't any more context to it. I was looking into if it actually was possible, but without assigning the numbers itself.

I think Mike's idea of ordering is a good way to do this (again, for a fixed set of types) without having to explicitly assign numbers: they're implicitly given by the ordering. However, I think that this would be easier by using a type list. The index of any type in the list would be its number. I think something like the following might do:

// basic type list manipulation stuff
template< typename T1, typename T2, typename T3...>
struct type_list;

// meta function, List is assumed to be some instance of type_list
template< typename T, class List >
struct index_of {
  enum { result = /* find index of T in List */ };
};

// the list of types you support
typedef type_list<AClass, BClass, CClass> the_type_list;

// your meta function
template< typename T >
struct type2int
{
   enum { result = index_of<T, the_type_list>::result };
};
like image 155
sbi Avatar answered Nov 15 '22 23:11

sbi


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!)

like image 30
Matthew Herrmann Avatar answered Nov 15 '22 21:11

Matthew Herrmann


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(){};
};
like image 39
Houe Avatar answered Nov 15 '22 22:11

Houe