Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is generating unique ID from template template parameters UB?

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";
}
like image 305
B.D Avatar asked Oct 31 '21 14:10

B.D


People also ask

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

Can we pass Nontype parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

What can the template parameter in C++ template definition be?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

When is a non-type template parameter unmodifiable?

When the name of a non-type template parameter is used in an expression within the body of the class template, it is an unmodifiable prvalue unless its type was an lvalue reference type, or unless its type is a class type (since C++20) .

What is a type parameter in a template?

Type template parameter. In the body of the template declaration, the name of a type parameter is a typedef-name which aliases the type supplied when the template is instantiated. There is no difference between the keywords class and typename in a type template parameter declaration.

Is there a way to get the uniquestring of a template?

There is a function that has been released recently that will help you a lot with this need, the uniqueString () function. Having a unique value each time you perform a deployment is not very useful when dealing with ARM template.

How do I parameterize a template?

Every template is parameterized by one or more template parameters, indicated in the parameter-list of the template declaration syntax: template < parameter-list > declaration Each parameter in parameter-list may be: a non-type template parameter;


1 Answers

There is no UB here. The template GetID is instantiated once for each unique template argument, but GCC wrongly treats the alias templates as the template they alias itself, because they are equivalent here, as Davis Herring pointed out.

I think the simplest general solution is to pass the argument types in the alias templates through another alias template that makes them dependent names.

template<class Type> struct typeAlias { using AliasedType = Type; };
template<class Type> using AliasType = typename typeAlias<Type>::AliasedType;

template<typename T>
struct S {};
struct W1 { template<typename A> using type = S<AliasType<A>>; };
struct W2 { template<typename A> using type = S<AliasType<A>>; };
like image 133
Radoslav Voydanovich Avatar answered Dec 09 '22 12:12

Radoslav Voydanovich