<details open><summary>Info</summary><p> * **Did you know that tuple can be implement just with lambdas?** * https://eel.is/c++draft/tuple </p></details><details open><summary>Example</summary><p> ```cpp constexpr auto tuple = [][[nodiscard]](auto... args) { return [=][[nodiscard]](auto fn) { return fn(args...); }; }; constexpr auto apply(auto fn, auto t) { return t(fn); }; static_assert(0 == apply([](auto... args) { return sizeof...(args); }, tuple())); static_assert(1 == apply([](auto... args) { return sizeof...(args); }, tuple(1))); static_assert(2 == apply([](auto... args) { return sizeof...(args); }, tuple(1, 2))); ``` > https://godbolt.org/z/xTf9nMqPY </p></details><details open><summary>Puzzle</summary><p> * **Can you implement get by number/type for lambda based tuple?** * Double points for not using std::tuple! ```cpp constexpr auto tuple = [][[nodiscard]](auto... args) { return [=][[nodiscard]](auto fn) { return fn(args...); }; }; template<auto N> [[nodiscard]] constexpr auto get(auto t); // TODO template<class T> [[nodiscard]] constexpr auto get(auto t); // TODO static_assert(1 == get<0>(tuple(1, 2, 3))); static_assert(2 == get<1>(tuple(1, 2, 3))); static_assert(3 == get<2>(tuple(1, 2, 3))); static_assert('a' == get<0>(tuple('a', 42, 77.))); static_assert(42 == get<1>(tuple('a', 42, 77.))); static_assert(77. == get<2>(tuple('a', 42, 77.))); static_assert(42 == get<int>(tuple('a', 42, 77.))); static_assert(77. == get<double>(tuple('a', 42, 77.))); static_assert('a' == get<char>(tuple('a', 42, 77.))); ``` > https://godbolt.org/z/jcsj51MG3 </p></details><details><summary>Solutions</summary><p> ```cpp #include <type_traits> #include <utility> template<::std::size_t N, class ... Args> struct nth_type ; template<class T, class ... Args> struct nth_type<0, T, Args...> : ::std::type_identity<T> {}; template<::std::size_t N, class T, class ... Args> struct nth_type<N, T, Args...> : nth_type<N-1, Args...> {}; template<auto N> [[nodiscard]] constexpr auto get(auto t) { auto func = []<class ... Args> (Args ... args) { typename nth_type<N, Args...>::type result; auto impl = [Count = 0] (auto input, auto & result) mutable { if (Count == N) { result = input; } ++Count; }; (impl(args, result), ...); return result; }; return t(func); } template<class T> [[nodiscard]] constexpr auto get(auto t) { auto func = []<class ... Args> (Args ... args) { T result; auto impl = [has_val = false]<class Arg> (Arg input, auto & result) mutable { if (::std::is_same_v<T, Arg> && not has_val) { result = input; has_val = true; } }; (impl(args, result), ...); return result; }; return t(func); } ``` > https://godbolt.org/z/be7YTW5P5 ```c++ namespace detail { template <std::size_t N, typename T> struct elem_by_index { T &ref; }; template <typename T> struct elem_by_type { T &ref; }; } // namespace detail template <auto N> [[nodiscard]] constexpr auto get(auto t) { return t([]<typename... Ts>(Ts... elems) { return [&]<std::size_t... Is>(std::index_sequence<Is...>) { struct all_elems : detail::elem_by_index<Is, Ts>... {}; return []<typename U>(const detail::elem_by_index<N, U> &elem) { return elem.ref; }(all_elems{elems...}); }(std::index_sequence_for<Ts...>{}); }); } template <class T> [[nodiscard]] constexpr auto get(auto t) { return t([]<typename... Ts>(Ts... elems) { struct all_elems : detail::elem_by_type<Ts>... {}; return [](const detail::elem_by_type<T> &elem) { return elem.ref; }(all_elems{elems...}); }); }; ``` > https://godbolt.org/z/qnY6WdYY9 ```cpp namespace detail { template <class T, std::size_t> struct tag { T value; }; constexpr auto get(auto visitor) { return [=]<class... Ts>(Ts... args) { return [&]<auto... Ns>(std::index_sequence<Ns...>) { struct : tag<Ts, Ns>... { } values{{.value = args}...}; return visitor(values); }(std::index_sequence_for<Ts...>{}); }; } } // namespace detail template <std::size_t N> [[nodiscard]] constexpr auto get(auto t) { return t(detail::get( []<class T>(detail::tag<T, N> &element) { return element.value; })); } template <class T> [[nodiscard]] constexpr auto get(auto t) { return t(detail::get( []<auto N>(detail::tag<T, N> &element) { return element.value; })); } ``` > https://godbolt.org/z/hb8W7z3YW ```cpp template <auto N, auto I> requires (I <= N) constexpr auto get_by_index(auto first, auto... rest) { if constexpr (I == N) { return first; } else { return get_by_index<N, I + 1>(rest...); } }; template<auto N> [[nodiscard]] constexpr auto get(auto t) { return t([](auto... args) { return get_by_index<N, 0>(args...); }); } template <class T> constexpr auto get_by_type(auto first, auto... rest) { if constexpr (std::is_same<T, decltype(first)>()) { return first; } else { return get_by_type<T>(rest...); } }; template<class T> [[nodiscard]] constexpr auto get(auto t) { return t([](auto... args) { return get_by_type<T>(args...); }); ``` > https://godbolt.org/z/s3qrPv9GG ```cpp constexpr auto ignore_first = [][[nodiscard]](auto first, auto... args) { return [=][[nodiscard]](auto fn) { return fn(args...); }; }; constexpr auto get_first = [][[nodiscard]](auto first, auto... args) { return first; }; template<auto N> [[nodiscard]] constexpr auto get(auto t) { if constexpr (N == 0){ return t(get_first); }else{ return get<N-1>(t(ignore_first)); } }; template<class T> [[nodiscard]] constexpr auto get(auto t){ if constexpr(std::is_same_v<T,decltype(t(get_first))>){ return t(get_first); }else{ return get<T>(t(ignore_first)); } } ``` > https://godbolt.org/z/TP31x6xca ```cpp template <class T, std::size_t N> struct any { T value{}; }; constexpr auto indicies = [](auto fn) { return [fn]<class... Ts>(Ts... args) { return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) { struct : any<Ts, Ns>... { } _{args...}; return fn(_); }(std::make_index_sequence<sizeof...(args)>{}); }; }; template <auto N> [[nodiscard]] constexpr auto get(auto t) { return t(indicies([]<class T>(any<T, N>& t) { return t.value; })); } template <class T> [[nodiscard]] constexpr auto get(auto t) { return t(indicies([]<auto N>(any<T, N>& t) { return t.value; })); ``` > https://godbolt.org/z/YbMbrGWdn ```cpp template<auto N> constexpr auto nth_index = [](auto arg1, auto... args) { if constexpr(N == 0) { return arg1; } else { return nth_index<N-1>(args...); } }; template<auto N> [[nodiscard]] constexpr auto get(auto t) { return t(nth_index<N>); } template<typename T> constexpr auto Tth_type = [](auto arg1, auto... args) { if constexpr(std::is_same_v<decltype(arg1),T>) { return arg1; } else { return Tth_type<T>(args...); } }; template<class T> [[nodiscard]] constexpr auto get(auto t) { return t(Tth_type<T>); ``` > https://godbolt.org/z/so3q8a67h ```cpp template<auto N> auto getNth = [](auto t, auto...ts) { if constexpr(N==0) return t; else return getNth<N-1>(ts...); }; template<typename T> auto getT = [](auto t, auto...ts) { if constexpr( std::is_same_v<T, decltype(t)> ) return t; else return getT<T>(ts...); }; template<auto N> [[nodiscard]] constexpr auto get(auto t) { return t(getNth<N>); } template<class T> [[nodiscard]] constexpr auto get(auto t) { return t(getT<T>); ``` > https://godbolt.org/z/YvcavT8E9 ```cpp constexpr auto apply(auto fn, auto t) { return t(fn); }; template <typename T, std::size_t N> struct enumerated { T value{}; }; constexpr auto get_by(auto fn) { return [=]<typename... Ts>(Ts... args) { return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) { struct _ : enumerated<decltype(args), Ns>... { } args_and_ns{args...}; return fn(args_and_ns); }(std::make_index_sequence<sizeof...(args)>{}); }; }; template <std::size_t N> [[nodiscard]] constexpr auto get(auto t) { return apply(get_by([]<typename T>(enumerated<T, N>& t) { return t.value; }), t); } template <typename T> [[nodiscard]] constexpr auto get(auto t) { return apply(get_by([]<std::size_t N>(enumerated<T, N>& t) { return t.value; }), t); } ``` > https://godbolt.org/z/G4zToq8K ```cpp template<class T, std::size_t N> struct any { T value{}; }; template<auto N> [[nodiscard]] constexpr auto get(auto t){ return t([](auto... args) { return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) { struct : any<decltype(args), Ns>... { } _{args...}; return []<class K>(any<K, N>& x) { return x.value; }(_); } (std::make_index_sequence<sizeof...(args)>{}); }); } template<class T> [[nodiscard]] constexpr auto get(auto t){ return t([](auto... args) { return (... + [](auto x){ if constexpr(std::is_same_v<T, decltype(x)>) return x; else return 0; }(args)); }); } ``` > https://godbolt.org/z/rhMheWYhd ```cpp template <auto N> [[nodiscard]] constexpr auto get(auto t) { return t([](auto... args) { return [&]<auto... Ns>(std::index_sequence<Ns...>) { return [](decltype((void*)Ns)..., auto* nth, auto*...) { return *nth; }(&args...); }(std::make_index_sequence<N>()); }); } ``` > https://godbolt.org/z/a7GrWPz8j