Created
July 11, 2024 19:54
-
-
Save topin89/73211e0045c8d1ae08f7beaf79a37cc8 to your computer and use it in GitHub Desktop.
Решение задачи linuxnyasha с выщёлкиванием типов из списка типов по переданным индексам
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
// ---------------- Исходные типы | |
// Структура используется только как хранилище типов | |
// Наверняка можно сделать так, чтобы её можно было сделать | |
// только внутри declspec, но зачем нам троллейбус из буханки, | |
// и так непросто вышло | |
template <typename... Ts> | |
struct TypeList {}; | |
// Тип чисто для удобства. В оригинале тут были | |
// операторы для конверсии значений в сами значения, | |
// но код и так большой, а нам не требуется, так что я их убрал | |
template <auto V> | |
struct Wrapper{}; | |
// Этот тип нужен только для того, чтобы писать | |
// kTypeList{Wrapper<1>, Wrapper<2>, ...} | |
// вместо | |
// TypeList<Wrapper<1>, Wrapper<2>, ...>{} | |
template <typename... Ts> | |
constexpr TypeList<Ts...> kTypeList{}; | |
// ---------------- Решение задачи | |
// Эта функция проверяет, есть ли один конкретный индекс | |
// в списке индексов | |
template <size_t first, size_t... tail> | |
constexpr bool has_index(size_t index) { | |
if constexpr(sizeof...(tail) == 0){ | |
return index == first; | |
} | |
else{ | |
return index == first ? true : has_index<tail...>(index); | |
} | |
} | |
// Эта функция проверяет, не выходят ли индексы | |
// за размеры списка типов | |
template <size_t first, size_t... tail> | |
constexpr bool all_indices_are_valid(size_t num_of_types) { | |
if constexpr(sizeof...(tail) == 0){ | |
return first < num_of_types; | |
} | |
else{ | |
return first < num_of_types ? all_indices_are_valid<tail...>(num_of_types) : false ; | |
} | |
} | |
// Эта функция превращает произвольный список индексов TypeListTypes... | |
// В список типов, состоящий только из первого элемента списка | |
template<typename FirstType, typename... TypeListTypes> | |
auto First(){ | |
return TypeList<FirstType>{}; | |
} | |
// Эта функция превращает произвольный список индексов TypeListTypes... | |
// В список типов, состоящий из всех типов в списке, кроме первого | |
template<typename FirstType, typename... TypeListTypes> | |
auto Remainder(){ | |
return TypeList<TypeListTypes...>{}; | |
} | |
// Эта функция превращает произвольный список индексов TypeListTypes... | |
// В список типов, состоящий только из первого элемента списка, | |
// если index есть в списке indices..., а иначе в пустой TypeList | |
template<size_t index, size_t... indices, typename... TypeListTypes> | |
constexpr auto FirstOrNothing(TypeList<TypeListTypes...>){ | |
if constexpr(has_index<indices...>(index)){ | |
return TypeList<>{}; | |
}else{ | |
return First<TypeListTypes...>(); | |
} | |
} | |
// Эта функция просто объединяет два списка TypeList в один. | |
// Забавно, но именно над этой задачей, слияния двух списков, | |
// я бился больше всего | |
template<typename... Left, typename... Right> | |
constexpr auto ConcatTypes(TypeList<Left...>, TypeList<Right...>){ | |
return TypeList<Left..., Right...>{}; | |
} | |
// Вспомогательная функция для VariadicPop. | |
// Если TypeListTypes... пустой, просто возвращаем пустой TypeList | |
// Если нет, то находим, нужен ли нам первый элемент TypeListTypes... | |
// и либо его, либо пустой TypeList сливаем с оставшимися элементами, | |
// которые рекурсивно обходим. Чесслово, код тут понятнее описания будет | |
template<size_t index, size_t... indices, typename... TypeListTypes> | |
constexpr auto VariadicPopHelper(TypeList<TypeListTypes...>){ | |
if constexpr(sizeof...(TypeListTypes) == 0){ | |
return TypeList<>{}; | |
} | |
else{ | |
const auto left = FirstOrNothing<index, indices...>(TypeList<TypeListTypes...>{}); | |
return ConcatTypes(left, VariadicPopHelper<index + 1, indices...>(Remainder<TypeListTypes...>())); | |
} | |
} | |
// Та самая функция для константного выщёлкивания элементов | |
// списка типов по индексу | |
// Если индексов нет, просто возвращаем исходный список типов | |
// Если список типов пустой, проверям, что список индексов пустой | |
// и возвращаем пустой список | |
// Иначе проверям, что индексы не выходяд за размер списка типов | |
// и возвращаем VariadicPopHelper, начиная перебор с нулевого индекса | |
template<size_t... indices, typename... TypeListTypes> | |
auto VariadicPop(TypeList<TypeListTypes...> types) { | |
if constexpr(sizeof...(indices) == 0){ | |
return types; | |
} | |
else if constexpr(sizeof...(TypeListTypes) == 0){ | |
static_assert(sizeof...(indices) == 0 ); | |
return TypeList<>{}; | |
} | |
else { | |
static_assert(all_indices_are_valid<indices...>(sizeof...(TypeListTypes))); | |
return VariadicPopHelper<0, indices...>(types); | |
} | |
} | |
// ---------------- Проверки | |
int main() { | |
static_assert(has_index<1, 3, 5>(1) == true); | |
static_assert(all_indices_are_valid<1, 3, 5>(6) == true); | |
static_assert(all_indices_are_valid<1, 3, 5>(5) == false); | |
static_assert(all_indices_are_valid<6, 3, 5>(1) == false); | |
static_assert(std::is_same_v< | |
decltype(FirstOrNothing<4, 1, 3, 5>( | |
kTypeList< | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3> | |
> | |
)), | |
TypeList< Wrapper<1>> | |
>); | |
static_assert(std::is_same_v< | |
decltype(ConcatTypes( | |
kTypeList< | |
Wrapper<1>, | |
Wrapper<2> | |
>, | |
kTypeList< | |
Wrapper<3> | |
> | |
)), | |
TypeList< Wrapper<1>, Wrapper<2>, Wrapper<3> > | |
>); | |
static_assert(std::is_same_v< | |
decltype(ConcatTypes( | |
kTypeList< | |
Wrapper<1>, | |
Wrapper<2> | |
>, | |
kTypeList< > | |
)), | |
TypeList< Wrapper<1>, Wrapper<2> > | |
>); | |
static_assert(std::is_same_v< | |
decltype(VariadicPop<1>( | |
kTypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5>, | |
Wrapper<6> | |
> | |
)), | |
TypeList< | |
Wrapper<0>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5>, | |
Wrapper<6> | |
> | |
>); | |
static_assert(std::is_same_v< | |
decltype(VariadicPop<6>( | |
kTypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5>, | |
Wrapper<6> | |
> | |
)), | |
TypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5> | |
> | |
>); | |
static_assert(std::is_same_v< | |
decltype(VariadicPop<>( | |
kTypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5>, | |
Wrapper<6> | |
>)), | |
TypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5>, | |
Wrapper<6> | |
> | |
>); | |
static_assert(std::is_same_v< | |
decltype(VariadicPop<>( | |
kTypeList<> | |
) | |
), | |
TypeList<> | |
>); | |
// Ошибка | |
// VariadicPop<1>(kTypeList<>); | |
// Ошибка | |
// VariadicPop<3>(kTypeList< Wrapper<1> >); | |
static_assert(std::is_same_v< | |
decltype(VariadicPop<3, 1, 4>( | |
kTypeList< | |
Wrapper<0>, | |
Wrapper<1>, | |
Wrapper<2>, | |
Wrapper<3>, | |
Wrapper<4>, | |
Wrapper<5> | |
> | |
) | |
), | |
TypeList< | |
Wrapper<0>, | |
Wrapper<2>, | |
Wrapper<5> | |
> | |
>); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment