boost::hana: 为啥我不能过滤一个集合?

Posted

技术标签:

【中文标题】boost::hana: 为啥我不能过滤一个集合?【英文标题】:boost::hana: Why can't I filter a set?boost::hana: 为什么我不能过滤一个集合? 【发布时间】:2018-09-30 12:15:17 【问题描述】:

我正在使用 boost::hana,我想过滤一个 boost::hana::set。

#include <boost/hana.hpp>
#include <type_traits>

int main()
    using namespace boost::hana;
    auto a = make_set(1,'a',3);
    auto b = remove_if(a, [](const auto& x)return bool_c<std::is_same_v<decltype(x), char>>;);
    // expects b to be make_set(1, 3);

这会导致 static_assert 失败。它告诉我:

static assertion failed: hana::remove_if(xs, predicate) requires 'xs' to be a MonadPlus

         static_assert(hana::MonadPlus<M>::value, 

为什么会失败?为什么集合不能是 MonadPlus,即使定义了空集合和连接操作?

【问题讨论】:

可能是因为集合不是序列,因为set s 必须包含唯一元素。如果你想要更具体的东西,那么你可以在hana 的代码中找到hana::MonadPlus 的定义,然后再返回看看hana::set 缺少哪些先决条件。 这是一个完全合法且可以回答的问题。为什么它被否决了? 【参考方案1】:

如果你想过滤一个列表,你应该使用hana::tuple。 Set 的概念比 MonadPlus 甚至 Monad 更普遍。您断言hana::set 具有hana::concathana::empty 的实现是不正确的,此外它还要求数据结构是Monad。

根据您的示例,您正在寻找的可能是hana::difference,但hana::set 本身对此毫无用处。它的操作需要hana::Comparable 并且不能很好地适应运行时状态。

如果您想按类型“过滤”集合并维护运行时值,我建议使用同样支持集合操作的hana::map。您可以将其键设为其值的hana::type。这仍然需要其类型的唯一性。

这是一个例子:

#include <boost/hana.hpp>

namespace hana = boost::hana;

constexpr auto typed_set = [](auto&& ...x) 
  return hana::make_map(
    hana::make_pair(hana::typeid_(x), std::forward<decltype(x)>(x))...
  );
;

int main() 
  auto a = typed_set(1, 'a', 3.0f);
  auto b = typed_set('c');
  auto c = hana::difference(a, b);

  BOOST_HANA_RUNTIME_ASSERT(c == typed_set(1, 3.0f));

【讨论】:

以上是关于boost::hana: 为啥我不能过滤一个集合?的主要内容,如果未能解决你的问题,请参考以下文章

Boost Hana 编译时列表转换

Boost hana 获取字符串类型

如何将 boost::hana::tuple 转换为 std::variant

Boost.Hana在visual studio 2017 rc中的残缺使用

减轻头文件中的长限定

为啥我不能像使用列表一样过滤 IQueryable?