3

Is there a concise way to get a sequence of indices of tuple elements which satisfy a predicate in Hana?

Here's the code I wrote for that using just the standard library:

template <template<typename> typename Pred, typename Tuple>
class get_indices_of {
  static constexpr size_t size = std::tuple_size<Tuple>::value;
  template <size_t I, size_t... II> struct impl {
    using type = std::conditional_t<
      Pred<std::tuple_element_t<I,Tuple>>::value,
      typename impl<I+1, II..., I>::type,
      typename impl<I+1, II...>::type >;
  };
  template <size_t... II> struct impl<size,II...> {
    using type = std::index_sequence<II...>;
  };
public:
  using type = typename impl<0>::type;
};
template <template<typename> typename Pred, typename Tuple>
using get_indices_of_t = typename get_indices_of<Pred,Tuple>::type;

Usage example:

using types = std::tuple<std::string,int,double,char>;
using ints = get_indices_of_t<std::is_integral,types>;

The type of ints is now std::index_sequence<1ul, 3ul>.

SU3
  • 5,064
  • 3
  • 35
  • 66
  • What's wrong with your code? It's just going to be squirreled away in a library header anyways, so who cares if it's a little convoluted. I have a few ideas of how this could be done differently, but without knowing what the issue with your current approach is, it's hard to figure out what would be best. –  Jul 05 '17 at 20:42
  • There's no problem with my code. I posted it as an explanation of what I want to do. I just want to know if Hana has an algorithm for this. – SU3 Jul 05 '17 at 20:46

1 Answers1

2

I'd guess something like this:

constexpr auto get_indices_of = [](auto tuple, auto predicate){
    constexpr auto indices = to<tuple_tag>(range_c<std::size_t, 0, size(tuple)>);
    return filter(indices, [=](auto i){ return predicate(tuple[i]); }); 
};

The only awkward part there is getting the indices, since range_c itself isn't a MonadPlus. Your actual example, using this function, is:

constexpr auto types = make_tuple(
    type_c<std::string>, type_c<int>, type_c<double>, type_c<char>);
constexpr auto ints = get_indices_of(types, trait<std::is_integral>);
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 3
    Cats and dogs answering each others metaprogramming questions - Mass hysteria! BTW there is also an open request for this feature https://github.com/boostorg/hana/issues/273 – Jason Rice Jul 05 '17 at 22:43
  • 1
    Technically, the reason why you need `to(range_c<...>)` is because `range_c` is not a `MonadPlus` (see [this](http://boostorg.github.io/hana/group__group-MonadPlus.html)), not because it's not a `Sequence`. This is just a nitpick, and your answer is otherwise correct. – Louis Dionne Jul 07 '17 at 05:34
  • @LouisDionne Must be using an old pull of hana, I swear the static assert said it had to be a Sequence - definitely says MonadPlus. Woops. – Barry Jul 07 '17 at 12:01