Skip to content

Latest commit

 

History

History
381 lines (307 loc) · 9.59 KB

304.md

File metadata and controls

381 lines (307 loc) · 9.59 KB
Info

Example

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

Puzzle

  • Can you implement get by number/type for lambda based tuple?

    • Double points for not using std::tuple!
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

Solutions

#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

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

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

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

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

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

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

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

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

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

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