I am trying to make a function that will take in some data types (through variadic templates) and return a unique integer for each combination of data types. It should return the same integer no matter the order of the data types; for instance, GetNumber<int, double>()
should return the same integer as GetNumber<double, int>()
. The purpose for this is to index from an array/lookup in an unordered map which will store a MyClass<DataTypes>
at that position. Essentially, I am trying to get the corresponding object for any given combination of data types.
Thank you for taking the time to read this, I really appreciate it.
As long as they don't have to be consecutive, you can construct unique identifiers for type lists by using the fact that integers have unique decompositions into primes.
Using the functions from Generating prime numbers at compile time, we can assign unique prime numbers to every individual type ...
std::size_t typeIdGen() {
static std::size_t n = 0;
return n++;
}
template <typename>
std::uint64_t typePrime() { // assigns a unique prime for each distinct type
static std::uint64_t const p = primeAtIndex(typeIdGen());
return p;
}
... and then simply multiply them for the variadic type list:
template <typename... Ts>
std::uint64_t uniqueId() {
return (typePrime<Ts>() * ... * 1);
}
Check out the demo on compiler explorer.
std::cout << "(none): " << uniqueId<>() << '\n';
std::cout << "int, float: " << uniqueId<int,float>() << '\n';
std::cout << "float, int: " << uniqueId<float,int>() << '\n';
std::cout << "double, bool, void*: " << uniqueId<double,bool,void*>() << '\n';
std::cout << "int: " << uniqueId<int>() << '\n';
outputs:
(none): 1
int, float: 6
float, int: 6
double, bool, void*: 385
int: 2