Boost hana get index of first matching

2019-02-25 12:03发布

So I am trying to make a library using boost::hana that requires the functionality to get the index of a element based on the value:

constexpr auto tup = boost::hana::make_tuple(3_c, boost::hana::type_c<bool>);

auto index = get_index_of_first_matching(tup, boost::hana::type_c<bool>);
//   ^^^^^ would be a boost::hana::int_<1>

Is there a possible way to do this? Better yet, is it already in hana and I don't know about it?

Thanks for the support!

2条回答
做自己的国王
2楼-- · 2019-02-25 12:47

Hana does not provide an algorithm to do this out-of-the-box. If it seems like a much desired feature, I could add such an algorithm fairly easily. It would probably fit well as part of the interface of any Iterable, since Iterables are those sequences for which indices are meaningful.

For the time being, I would go with something very close to what @cv_and_he proposed in his comment:

#include <boost/hana.hpp>
namespace hana = boost::hana;

template <typename Iterable, typename T>
constexpr auto index_of(Iterable const& iterable, T const& element) {
    auto size = decltype(hana::size(iterable)){};
    auto dropped = decltype(hana::size(
        hana::drop_while(iterable, hana::not_equal.to(element))
    )){};
    return size - dropped;
}

constexpr auto tuple = hana::make_tuple(hana::int_c<3>, hana::type_c<bool>);
constexpr auto index = index_of(tuple, hana::type_c<bool>);
static_assert(index == hana::size_c<1>, "");

int main() { }

A few notes about the above code. First, indices are required to be non-negative in Hana, so it is probably a good idea to use an unsigned type. Secondly, I'm using hana::drop_while instead of hana::take_while, because the former only requires an Iterable, while the latter requires a Sequence. While it may seem like I'm doing more work (computing the size twice), it turns out that computing the size of most sequences you'll encounter is very fast, so it's not really a concern. Finally, I'm enclosing the hana::size(hana::drop_while(...)) in decltype, which ensures that no work whatsoever will be done at runtime.

查看更多
冷血范
3楼-- · 2019-02-25 12:52

How about using boost::detail::index_if:

#include <boost/hana.hpp>

template <typename Haystack, typename Needle>
constexpr auto get_index_of_first_matching(Haystack&&, Needle&& n)
{
  using Pred = decltype(boost::hana::equal.to(n));
  using Pack = typename boost::hana::detail::make_pack<Haystack>::type;
  constexpr auto index = boost::hana::detail::index_if<Pred, Pack>::value;
  return boost::hana::int_c<index>;
}

int main()
{
  using namespace boost::hana::literals;
  constexpr auto tup = boost::hana::make_tuple(3_c, boost::hana::type_c<bool>);
  constexpr auto index = get_index_of_first_matching(tup, boost::hana::type_c<bool>);
  static_assert(index == boost::hana::int_c<1>, "index is wrong");
  return 0;
}
查看更多
登录 后发表回答