Info
- Did you know about methods to access the last element of variadic pack...?
Example
template<class, std::size_t> concept Any = true;
constexpr auto last1 = [](auto... args) {
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
return [](Any<Ns> auto..., auto last) {
return last;
}(args...);
}
(std::make_index_sequence<sizeof...(args) - 1>{});
};
auto last2 = [](auto... args) {
return (args, ...);
};
static_assert(1 == last1(1));
static_assert(2 == last1(1, 2));
static_assert(3 == last1(1, 2, 3));
static_assert(1 == last2(1));
static_assert(2 == last2(1, 2));
static_assert(3 == last2(1, 2, 3));
Puzzle
- Can you implement nth_element which returns Nth element of variadic pack...?
template<auto N>
constexpr auto nth_element; // TODO
static_assert(1 == nth_element<0>(1));
static_assert(1 == nth_element<0>(1, 2));
static_assert(2 == nth_element<1>(1, 2));
static_assert(1 == nth_element<0>(1, 2, 3));
static_assert(2 == nth_element<1>(1, 2, 3));
static_assert(3 == nth_element<2>(1, 2, 3));
Solutions
template<auto N>
constexpr auto nth_element = [](auto...args){
return std::get<N>(std::tuple{args...});
};
template <typename, std::size_t> concept prefix = true;
template <auto N>
constexpr auto nth_element(auto... args) {
return [&]<auto... Is>(std::index_sequence<Is...>) {
return [] (prefix<Is> auto..., auto arg, auto...) {
return arg;
}(args...);
}(std::make_index_sequence<N>());
}
template<class T, std::size_t N> struct any { T value{}; };
template<std::size_t N, class T>
constexpr decltype(auto) get(any<T, N>& t) { return t.value; }
template<auto N>
constexpr auto nth_element = [](auto... args) {
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
struct : any<decltype(args), Ns>... { } _{args...};
return get<N>(_);
}
(std::make_index_sequence<sizeof...(args)>{});
};
template<auto N>
constexpr auto nth_element = [](auto... args) {
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
return [](decltype((void*)Ns)..., auto* nth, auto*...) {
return *nth;
}(&args...);
}
(std::make_index_sequence<N>{});
};
template<class T, std::size_t N> struct any { T value{}; };
template<auto N>
constexpr auto nth_element = [](auto... args) {
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
struct : any<decltype(args), Ns>... { } _{args...};
return static_cast<__type_pack_element<N, any<decltype(args), Ns>...>&>(_).value;
}
(std::make_index_sequence<sizeof...(args)>{});
};
template<auto N>
constexpr auto nth_element = [](auto arg, auto... args)
requires (std::is_same_v<decltype(arg), decltype(args)> and ...) {
return std::array{arg, args...}[N];
};
template<auto N, auto I = 0>
constexpr auto nth_element(auto arg, auto... args) {
if constexpr (I == N) {
return arg;
} else if constexpr (sizeof...(args) > 0u) {
return nth_element<N, I + 1>(args...);
}
}
template<class T, std::size_t N> struct any { T value{}; };
template<auto N>
constexpr auto nth_element = [](auto... args) {
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
struct : any<decltype(args), Ns>... { } _{args...};
return static_cast<boost::mp11::mp_at_c<boost::mp11::mp_inherit<any<decltype(args), Ns>...>, N>&>(_).value;
}
(std::make_index_sequence<sizeof...(args)>{});
};
template<class, std::size_t> concept Any = true;
template<auto N>
constexpr auto nth_element(auto... pack) {
return [&]<auto... Is>(std::index_sequence<Is...>) {
return [](Any<Is> auto..., auto arg, auto...) {
return arg;
}(pack...);
}(std::make_index_sequence<N>{});
}
template<class, std::size_t> concept Any = true;
template<auto N>
constexpr auto nth_element( auto ... args )
{
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
return [](Any<Ns> auto ..., auto nth, auto ... ) {
return nth;
}(args...);
}(std::make_index_sequence<N>{});
}
namespace detail {
#define NTH_ARG(Z, N, TYPE) TYPE arg##N,
#define NTH_ELEMENT(Z, N, TYPE) \
template <auto I> \
requires(I == N) constexpr decltype(auto) nth_element( \
BOOST_PP_REPEAT(BOOST_PP_INC(N), NTH_ARG, TYPE) TYPE...) { \
return arg##N; \
}
BOOST_PP_REPEAT(BOOST_PP_DEC(BOOST_PP_LIMIT_REPEAT), NTH_ELEMENT, auto &&)
#undef NTH_ELEMENT
#undef NTH_ARG
} // namespace detail
template <auto N> constexpr decltype(auto) nth_element(auto &&...args) {
return detail::nth_element<N>(args...);
}
template <class, std::size_t>
concept Any = true;
template <auto N> constexpr decltype(auto) nth_element(auto &&...args) {
return [&]<auto... Is>(std::index_sequence<Is...>) -> decltype(auto) {
return [](Any<Is> auto &&..., auto &&arg, auto &&...) -> decltype(auto) {
return arg;
}(args...);
}(std::make_index_sequence<N>{});
}
template <std::size_t N>
requires (N == 0)
constexpr auto nth_element(auto&& arg0, auto&&...) {
return arg0;
}
template <std::size_t N>
requires (N > 0) constexpr auto nth_element(auto&& arg0, auto&&... rest) {
return nth_element<N-1>(std::forward<decltype(rest)>(rest)...);
}
template<auto N>
constexpr auto nth_element = [](auto... args) {
static_assert(N < sizeof...(args));
return std::array{args...}[N];
};
template<auto N>
constexpr decltype(auto) nth_element(auto &&... args) {
using namespace boost::mp11;
return [&] <class... Ts> (mp_list<Ts...>) -> decltype(auto) {
return [] (Ts &&..., auto &&arg, auto &&...) -> decltype(auto) {
return arg;
}(std::forward<decltype(args)>(args)...);
}(mp_take_c<mp_list<decltype(args)...>, N>{});
}
template<std::size_t> struct Any
{
template<typename T > constexpr Any(T){}
};
template<auto N>
constexpr auto nth_element( auto ... args )
{
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
return [](Any<Ns> ..., auto nth, auto ... ) {
return nth;
}(args...);
}(std::make_index_sequence<N>{});
}