#include <iostream>
#include <type_traits>
#include <variant>
#include <functional>
#include <array>
template<typename Head, typename ... Types>
struct tuple_impl :tuple_impl<Types...>
{
Head head;
tuple_impl(Head&& a, Types... types) : tuple_impl<Types...>(types...), head{ a } {}
tuple_impl(Head& a, Types... types) : tuple_impl<Types...>(types...), head{ a } {}
};
template<typename Head>
struct tuple_impl<Head> {
Head head;
tuple_impl(Head&& a) : head{ a } {}
tuple_impl(Head& a) : head{ a } {}
};
template<typename T, typename Head_t>
const constexpr bool Is_unique() { // requires() couldnt work here for overloading
return true;
}
template<typename T, typename Head_t, typename... Tail>
const constexpr std::enable_if_t < (sizeof...(Tail) > 0), bool > Is_unique() {
return
!((std::is_same_v<T, Head_t>) && (Is_unique<T, Tail...>()))
&&
((std::is_same_v<T, Head_t>) || (Is_unique<T, Tail...>()));
}
template<typename Head_t, typename ... Types >
constexpr bool is_unique_from_after_on() {
return Is_unique<Head_t, Types...>();
};
template<typename Head_t>
constexpr bool is_unique_from_after_on() {
return true;
}
template<typename Head, typename ... Types>
struct tuple:tuple_impl<Types>... {
Head head;
using complex_elem = std::variant <
std::enable_if_t<
is_unique_from_after_on<Head, Types...>(), Head*
>,
std::enable_if_t <
is_unique_from_after_on<Types...>(), Types*
>...
>;
std::array<complex_elem, (sizeof...(Types))+1> book_keeper;
template<typename Head_, typename ... Types_>
constexpr tuple(Head_&& a, Types_&&... b ) :head{ std::forward<Head>(a) }, tuple_impl<Types>{std::forward<Types>(b)}...,
book_keeper{
&head, &(this->tuple_impl<Types>::head)...}
{
}
complex_elem operator[](size_t index) {
return book_keeper[index];
}
};
template<typename Head>
struct tuple<Head>{
Head head;
tuple(Head&& a ) : head{ a } {}
tuple(Head& a) : head{ a } {}
std::variant<Head*> operator[](size_t index) {
return head;
}
};
int main() {
tuple<int, double, float> list{1, 2.0, 3.0f};
std::cout << *std::get<0>(list[0]) << std::endl;
std::cout << *std::get<1>(list[1]) << std::endl;
std::cout << *std::get<2>(list[2]) << std::endl;
return 0;
}