#ifndef GEODE_CORE_META_TUPLE_HPP #define GEODE_CORE_META_TUPLE_HPP #include "common.hpp" #include #include namespace geode::core::meta { /* The Tuple class presents a nicer way to interact with parameter packs. * While this container is technically usable in other code, this is mostly * used for static reflection in function wrapping. Other applications will * usually be better covered by std::tuple. */ template class Tuple; template <> class Tuple<> { private: template class Element { private: Type value; protected: constexpr Type at(std::integral_constant&&) const { return this->value; } public: constexpr Element(Type value) : value(value) {} }; template class Elements : public Parents... { private: using Parents::at...; public: static constexpr size_t size = sizeof...(Parents); template constexpr decltype(auto) at() const { static_assert(i < size, "Out of range access!"); return this->at(std::integral_constant()); } }; template class elements_for_impl; template class elements_for_impl, Classes...> { public: using result = Elements...>; }; public: template using elements_for = typename elements_for_impl< std::make_index_sequence, Classes...>::result; template static auto make(Classes&&... values) { return Tuple { values... }; } }; template class Tuple : public Tuple<>::elements_for { private: using MyElements = Tuple<>::elements_for; public: template using type_at = decltype(std::declval().template at()); private: template class type_at_wrap_impl { public: using result = void; }; template class type_at_wrap_impl { public: using result = type_at; }; public: // MSVC literally shows internal compiler structures if I don't wrap this sometimes. template using type_at_wrap = typename type_at_wrap_impl::result; }; } #endif /* GEODE_CORE_META_TUPLE_HPP */