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

I have several types, and I want to "bind" the std::integral_constant value of a sequential identifier to each 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 do not know how to track the last used identifier . Ideally, I want something like:

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

Is there a way to determine and track the compilation time of lastUsedID ?

How can I solve this problem?


EDIT:

Explanations:

  • TypeInfo<...> must often be called in user code. The syntax should remain clear (the user does not know (need to know) a) / (manually increase) the compile time counter)
  • Typeinfo<T>::Id::value must always return the same value in the entire program. The initial value will be "bound" to the first instance, lastUsedID + 1 .
  • I can use all the features of C ++ 11 and C ++ 14.
  • Listing all types before calling TypeInfo<...> not the right solution.
+5
source share
2 answers

This is not possible, and it is fairly easy to understand why: Consider two compilation units. The unit of measurement is Type00 , but not Type01 , and the second unit sees Type01 , but not Type00 . In C ++ there is nothing (including C ++ 11 and C ++ 14) that can now tell the compiler in both compilation units that should order these types. Even adding some data to the object file for link time is too long, since you are requesting a compile time value. This is the fundamental concept of compilation units, which creates a tough barrier to the function you are asking for.

+2
source

You can do this with a list of types:

 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 not in the List , then IndexOf<List, T>::value is -1 . You can make this case be a compilation error by removing the ellipsis from the TypeList<>::indexOf(...) signature.

Using:

 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

+1
source

Source: https://habr.com/ru/post/1202890/


All Articles