Info
-
Did you know that with C++20 (constexpr containers) TMP can be achieved with STL?
Example
#include <ranges>
template <auto Begin, auto End, auto List>
auto slice = List
| std::ranges::views::drop(Begin)
| std::ranges::views::take(End);
static_assert(
slice<1_c, 2_c, boost::mp::list<int, double, float>()>
==
boost::mp::list<double, float>());
Puzzle
- Can you implement algorithim which returns either last or first element of the list depending on which one has bigger size?
list<byte[100], byte[200], byte[42]> -> byte[100] list<byte[100], byte[200], byte[142]> -> byte[142] list<byte[100], byte[1], byte[142]> -> byte[142]
template <auto List>
auto first_or_last_depending_on_size; // TODO
static_assert(first_or_last_depending_on_size<boost::mp::list<std::byte[42], std::byte[43]>()> ==
boost::mp::list<std::byte[43]>());
static_assert(first_or_last_depending_on_size<boost::mp::list<std::byte[42], std::byte[999], std::byte[43]>()> ==
boost::mp::list<std::byte[43]>());
static_assert(first_or_last_depending_on_size<boost::mp::list<std::byte[142], std::byte[999], std::byte[43]>()> ==
boost::mp::list<std::byte[142]>());
static_assert(first_or_last_depending_on_size<boost::mp::list<std::byte[1], std::byte[2], std::byte[3], std::byte[2]>()> ==
boost::mp::list<std::byte[2]>());
Solutions
template <auto List>
auto first_or_last_depending_on_size = [] consteval {
auto LastList = List | std::ranges::views::reverse | std::ranges::views::take(1_c);
if constexpr (auto FirstList = List | std::ranges::views::take(1_c); sizeof_list(FirstList) > sizeof_list(LastList)) {
return FirstList;
} else {
return LastList;
}
} ();
template<template<class... Ts> class TList, class... Ts>
[[nodiscard]] consteval auto sizeof_list(TList<Ts...>) { return (sizeof(Ts) + ...);}
template<template<class... Ts> class TList, class... Ts>
[[nodiscard]] consteval auto size(TList<Ts...>) { return sizeof...(Ts); }
template <auto List>
auto first = List | std::ranges::views::take(1_c);
template <auto List>
auto last = List | std::ranges::views::drop(std::integral_constant<std::size_t, size(List) - 1>());
template <auto List>
auto first_or_last_depending_on_size = boost::mp::list<
std::byte[std::max(sizeof_list(first<List>), sizeof_list(last<List>))]
>()
template <auto List>
auto first_or_last_depending_on_size = List | []<class...> {
using boost::mp::operator""_c;
auto first = List | std::ranges::views::take(1_c);
auto last = List | std::ranges::views::reverse | std::ranges::views::take(1_c);
auto size = []<class T> { return sizeof(T); };
if constexpr ((first | size) > (last | size)) {
return first;
} else {
return last;
}
};
template <auto List>
auto first_or_last_depending_on_size = List | []<class... Ts>(auto) {
using boost::mp::operator""_c;
auto first = List | std::ranges::views::take(1_c);
auto last = List | std::ranges::views::reverse | std::ranges::views::take(1_c);
auto size = [](auto list) { return list | []<class T> { return sizeof(T); }; };
return std::array{
(size(first)) > (size(last)) ?
boost::mp::meta{.index = 0} :
boost::mp::meta{.index = sizeof...(Ts) - 1}
};
};
template<template<class... Ts> class TList, class... Ts>
[[nodiscard]] consteval auto sizeof_list(TList<Ts...>) { return (sizeof(Ts) + ...);}
template <auto List>
constexpr auto first = List | std::ranges::views::take(1_c);
template <auto List>
auto last = first<List | std::ranges::views::reverse>;
template <auto List>
auto first_or_last_depending_on_size =
[] {
if constexpr (sizeof_list(first<List>) > sizeof_list(last<List>)) {
return first<List>;
} else {
return last<List>;
}
}();
template <auto List>
auto first_or_last_depending_on_size = List | [](boost::mp::concepts::meta auto types) {
return std::array{
types[0].size > types[types.size() - 1].size - 1 ?
boost::mp::meta{.index = 0} :
boost::mp::meta{.index = types.size()-1}
};
};
template <auto List>
auto first_or_last_depending_on_size = []{
constexpr auto first = List | std::views::take(1_c);
constexpr auto last = List | std::views::reverse | std::views::take(1_c);
if constexpr(sizeof_list(first) > sizeof_list(last)){
return first;
}
else{
return last;
}
}();
template <auto List>
auto first_or_last_depending_on_size = [] {
constexpr auto first = List | views::take(1_c);
constexpr auto last = List | views::reverse | views::take(1_c);
if constexpr (sizeof_list(first) > sizeof_list(last)) {
return first;
} else {
return last;
}
}();
template<template<class... Ts> class TList, class... Ts>
[[nodiscard]] consteval auto sizeof_list(TList<Ts...>) { return (sizeof(Ts) + ...);}
namespace rv = std::ranges::views;
template <auto List>
auto first = [] { return List | rv::take(1_c); };
template <auto List>
auto last = [] { return List | rv::reverse | rv::take(1_c); };
template <auto List>
auto first_or_last_depending_on_size = [] {
auto first_element = first<List>();
auto last_element = last<List>();
if constexpr (sizeof_list(first_element) > sizeof_list(last_element)) {
return first_element;
} else {
return last_element;
}
}();
template <auto List>
auto first_or_last_depending_on_size = List | [] (boost::mp::concepts::meta auto types) {
auto first = types.front();
auto last = types.back();
return std::array{first.size < last.size ? last : first};
};