Вот возможное решение, в основном основанное на шаблонах:
#include<cstddef>
#include<functional>
#include<iostream>
template<typename T>
struct wrapper {
using type = T;
constexpr wrapper(std::size_t N): N{N} {}
const std::size_t N;
};
template<typename... T>
struct identifier: wrapper<T>... {
template<std::size_t... I>
constexpr identifier(std::index_sequence<I...>): wrapper<T>{I}... {}
template<typename U>
constexpr std::size_t get() const { return wrapper<U>::N; }
};
template<typename... T>
constexpr identifier<T...> ID = identifier<T...>{std::make_index_sequence<sizeof...(T)>{}};
// ---
struct A {};
struct B {};
constexpr auto id = ID<A, B>;
int main() {
switch(id.get<B>()) {
case id.get<A>():
std::cout << "A" << std::endl;
break;
case id.get<B>():
std::cout << "B" << std::endl;
break;
}
}
Обратите внимание, что для этого требуется C ++ 14.
Все, что вам нужно сделать, чтобы связать последовательные идентификаторы со спискомТипы должны предоставить этот список переменной шаблона, как в примере выше:
constexpr auto id = ID<A, B>;
С этого момента вы можете получить данный идентификатор для данного типа с помощью метода get
:
id.get<A>()
И это все.Вы можете использовать его в операторе switch
по запросу и как показано в примере кода.
Обратите внимание, что, пока типы добавляются в список классов, с которыми связан числовой идентификатор, идентификаторы являютсято же самое после каждой компиляции и во время каждого выполнения.
Если вы хотите удалить тип из списка, вы все равно можете использовать поддельные типы в качестве заполнителей, например:
template<typename> struct noLonger { };
constexpr auto id = ID<noLonger<A>, B>;
Это гарантирует, что у A
больше нет ассоциированного идентификатора, а тот, который присвоен B
, не изменится.
Если вы не хотите определенно удалять A
, вы можете использовать что-то вроде:
constexpr auto id = ID<noLonger<void>, B>;
Или что угодно.