И это всё МОЁ

Захотелось странного (ну, почти): заставить работать std::apply с обьектом std::integer_sequence. Ведь последний – вполне себе кортеж.


А целью было бы упрощение паттерна (хз как называется) с обходом кортежей (С++17*):


template <typename Function, 
typename Tuple,
std::size_t... indexes>
void doFoonktion(Function f, Tuple t, std::index_sequence<indexes...>;) {
(static_cast<void>(f(std::get<indexes>(t))), ...);
}

template <typename Function,
typename Tuple>
void doFunction(Function f, Tuple t) {
doFoonktion(f, t, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}



До такого:


template <typename Function,
typename Tuple>
void doFunction(Function f, Tuple t) {
std::apply([](auto... index) {
(static_cast<void>(f(std::get<index>(t))), ...);
},
std::make_index_sequence<std::tuple_size_v<T>>{});
}




  • да, я знаю, что в С++20 можно явно делать шаблонные лямбды и второй «внешней» функции уже не надо было бы.


Значит сделать tuple_size и tuple_element для integer_sequence очень даже просто:


template <auto v>
using constant = std::integral_constant<decltype(v), v>;

template <typename T, T... values>
tuple_size<integer_sequence<T, values...>> : constant<sizeof...(values)>
{};

template <size_t i, typename T, T... values>
tuple_element<i, integral_sequence<T, values...>> { using type = T; };



Докостыливаем std::get:


template <std::size_t i, typename T, T first, T... rest>
T get(integer_sequence<T, first, rest...>;) {
if constexpr (i == 0)
return first;
else
return get<i - 1>(integer_sequence<T, rest...>{});
}

template <std::size_t i, typename T>
T get(integer_sequence<T>;) {
static_assert(i != i, "invalid index";);
}


После такого финта ушами начинает работать structured binding:


  auto [zero, one, two, three] = std::make_index_sequence<4>{};


Однако std::apply «не видит» нашего std::get, если заголовок <tuple> был включен ДО нашего определения get. Наверное там нету ADL: https://wandbox.org/permlink/GRDV7VEvalUWATlM


Есть идеи как сделать такое красиво/правильно? Ну и еще было бы круто вообще заставить std::apply работать с пользовательскими типами. Пока что на ум приходит только написание собственную реализацию std::apply c шлюхами и ADL.









 , ,