提升得到第一个匹配的索引

时间:2015-11-29 05:03:57

标签: c++ c++11 boost template-meta-programming boost-hana

所以我试图使用boost::hana创建一个库,它需要根据值获取元素索引的功能:

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>

有可能这样做吗?更好的是,它已经在hana而且我不知道它吗?

感谢您的支持!

2 个答案:

答案 0 :(得分:5)

Hana没有提供开箱即用的算法。如果它看起来像一个非常理想的功能,我可以相当容易地添加这样的算法。它可能很适合作为任何Iterable的接口的一部分,因为Iterable s是索引有意义的那些序列。

目前,我会选择与@cv_and_he在评论中提出的内容非常接近的内容:

#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() { }

关于上述代码的一些注释。首先,Hana中的索引必须是非负的,因此使用无符号类型可能是个好主意。其次,我使用hana::drop_while代替hana::take_while,因为前者只需要Iterable,而后者需要Sequence。虽然看起来我做了更多的工作(计算两次大小),但事实证明,计算你遇到的大多数序列的大小非常快,所以它并不是真正的问题。最后,我将hana::size(hana::drop_while(...))括在decltype中,这样可以确保在运行时无法完成任何工作。

答案 1 :(得分:0)

如何使用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;
}