问题
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, tolastUsedID + 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