Compile-time template `std::integral_constant` counter - how to implement it?

守給你的承諾、 提交于 2021-02-18 23:00:47

问题


I have several types and I want to "bind" an std::integral_constant sequential ID value to every type at compile-time.

Example:

struct Type00 { };
struct Type01 { };
struct Type02 { };
struct Type03 { };
struct TypeXX { };
struct TypeYY { };

template<typename T> struct TypeInfo
{
    using Id = std::integral_constant<int, ???>;
};

int main()
{
     cout << TypeInfo<Type00>::Id::value; // Should always print 0
     cout << TypeInfo<Type01>::Id::value; // Should always print 1
     cout << TypeInfo<Type02>::Id::value; // Should always print 2
     cout << TypeInfo<Type03>::Id::value; // Should always print 3
     cout << TypeInfo<TypeXX>::Id::value; // Should always print 4
     cout << TypeInfo<TypeYY>::Id::value; // Should always print 5
}

The problem is that I don't know how to keep track of the last used ID. Ideally, I want something like:

template<typename T> struct TypeInfo
{
    using Id = std::integral_constant<int, lastUsedID + 1>;
};

Is there any way to define and keep track of a compile-time lastUsedID?

How can I solve this problem?


EDIT:

Clarifications:

  • TypeInfo<...> needs to be frequently called in user code. The syntax must remain clear (the user doesn't (need to know there's a) / (manually increment the) compile-time counter)
  • Typeinfo<T>::Id::value must always return the same value in the whole program. The initial value will be "bound" on the first instantiation, to lastUsedID + 1.
  • I can use all C++11 and C++14 features.
  • Listing all types before calling TypeInfo<...> is not a proper solution.

回答1:


It is not possible and it's quite easy to see why: Consider two compilation units. Unit one sees type Type00, but not Type01, while unit two sees Type01 but not Type00. There is nothing in C++ (including C++11 and C++14) which could now tell the compiler in both compilation units which order those types should have. Even adding some data to the object file for link-time is too late, as you are asking for a compile-time value. This is the fundamental concept of compilation units which poses a hard barrier for the feature you are asking for.




回答2:


You could do this with a type list:

template <typename... Ts>
struct TypeList;

template <>
struct TypeList<>
{
    static const int size = 0;
    static std::integral_constant<int, -1> indexOf(...);
};

template <typename Head, typename... Tail>
struct TypeList<Head, Tail...> : TypeList<Tail...>
{
    static const int size = sizeof...(Tail) + 1;
    static std::integral_constant<int, sizeof...(Tail)> indexOf(Head&&);
    using TypeList<Tail...>::indexOf;
};

template <typename TypeList, typename T>
using IndexOf = std::integral_constant<int,
    TypeList::size - decltype(TypeList::indexOf(std::declval<T>()))::value - 1>;

If T is not present in List then IndexOf<List, T>::value is -1. You can cause this case to be a compile error instead, by removing the ellipsis from the signature TypeList<>::indexOf(...).

Usage:

struct Type00 { };
struct Type01 { };
struct Type02 { };
struct Type03 { };
struct TypeXX { };
struct TypeYY { };

using MyTypeList = TypeList<
    Type00,
    Type01,
    Type02,
    Type03,
    TypeXX,
    TypeYY
>;

int main()
{
    std::cout << IndexOf<MyTypeList, Type00>::value
              << IndexOf<MyTypeList, Type01>::value
              << IndexOf<MyTypeList, Type02>::value
              << IndexOf<MyTypeList, Type03>::value
              << IndexOf<MyTypeList, TypeXX>::value
              << IndexOf<MyTypeList, TypeYY>::value;
}

Demo



来源:https://stackoverflow.com/questions/25916933/compile-time-template-stdintegral-constant-counter-how-to-implement-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!