Skip to content

Instantly share code, notes, and snippets.

@topin89
Created July 11, 2024 19:54
Show Gist options
  • Save topin89/73211e0045c8d1ae08f7beaf79a37cc8 to your computer and use it in GitHub Desktop.
Save topin89/73211e0045c8d1ae08f7beaf79a37cc8 to your computer and use it in GitHub Desktop.
Решение задачи linuxnyasha с выщёлкиванием типов из списка типов по переданным индексам
#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