I am trying to generate unique IDs from template template parameters. I tried this function
inline size_t g_id = 1;
template<template<typename> typename T>
inline size_t GetID()
{
static size_t id = g_id++;
return id;
}
it works fine until used with alias templates
template<template<typename> typename T>
inline void print()
{
std::cout << GetID<T>() << "\n";
}
template<typename T>
struct S {};
struct W1 { template<typename A> using type = S<A>; };
struct W2 { template<typename A> using type = S<A>; };
int main()
{
print<S>();
print<W1::type>();
print<W2::type>();
std::cin.get();
}
MSVC
1
2
3
clang
1
2
3
gcc
1
1
1
Is any compiler correct here or is there UB somewhere?
Update
After reading some of the material linked from Davis Herring`s comment CG1286, an alias template does not need to have the same template name as the underlying template. To me this seems like it could go both ways so are all compilers compliant here?
With that I have come up with a different way to generate IDs from template template parameters which should avoid this problem but has some compromises. Requires that you specialize the template with a Tag type and create a static method which retrieves your ID.
Implementation
inline size_t g_id = 1;
template<typename T>
inline size_t GenerateID()
{
static size_t id = g_id++;
return id;
}
struct Tag {};
template<template<typename...> typename T, typename... Args, typename = decltype(sizeof(T<Args...>))>
inline size_t get_id_imp(int)
{
return T<Args...>::GetID();
}
template<template<typename...> typename T, typename... Args, std::enable_if_t<sizeof...(Args) < 16, bool> = true>//16 = max template args
inline size_t get_id_imp(...)
{
return get_id_imp<T, Args..., Tag>(0);
}
template<template<typename...> typename T, typename... Args, std::enable_if_t<sizeof...(Args) >= 16, bool > = true>
inline size_t get_id_imp(...)
{
return 0;
}
template<template<typename...> typename T>
inline size_t GetID()
{
return get_id_imp<T, Tag>(0);
}
Use
template<typename T>
struct X {};
template<> struct X<Tag> { static size_t GetID() { return GenerateID<X>(); } };
template<template<typename...> typename T>
inline void print()
{
std::cout << GetID<T>() << "\n";
}