I have a function:
template<typename... Args>
auto CallItemsInOrder(std::tuple<Args...> items)
{
// Magic here!
}
Where each item of the tuple has two qualities: A priority for which it should be called, and a function overload to call it with:
// DoWork calls are NOT constexpr
template<> void DoWork(int item) { ... }
template<> void DoWork(std::string item) { ... }
// std::string is higher priority than int, gets called first
// Priorities don't have to be unique or sequential, to allow future customization
template<> struct WorkPriority<int> { static constexpr int = 0; }
template<> struct WorkPriority<std::string> { static constexpr int = 10; }
Such that, when CallItemsInOrder
is called with that tuple, it should be able to be optimized down to this at compiletime:
template<>
auto CallItemsInOrder(std::tuple<int, std::string> items)
{
DoWork(std::get<1>(items));
DoWork(std::get<0>(items));
}
This is something I could imagine is easy to do without a hundred lines of code using Boost.Hana, but frankly I'm having trouble understanding the docs. Any help would be appreciated!
"Just" sort the indexes by priority (thanks to constexpr function):
template<typename... Args>
auto CallItemsInOrder(std::tuple<Args...> items)
{
[&]<std::size_t ... Is>(std::index_sequence<Is...>){
constexpr auto arr = [](){
// priority, index pairs
std::array<std::pair<int, std::size_t>, sizeof...(Is)> res{{
{WorkPriority<std::tuple_element_t<Is, std::tuple<Args...>>>::value, Is}...
}};
std::sort(res.begin(), res.end(), std::greater{}); // std::partial_sort, custom comparer, ...
return res;
}();
// now just call DoWork(std::get<arr[Is].index>(items)) in "loop".
(DoWork(std::get<std::get<1>(arr[Is])>(items)), ...);
}(std::index_sequence_for<Args...>());
}