与外部库集成
Hana
提供了与一些现有库的开箱即用集成。 具体来说,这意味着您可以使用Hana
算法中的这些库中的一些容器,只需包含适当的标头,使之成为Hana
和外部组件之间的桥梁。 这可以非常有用的移植现有代码从例如。 Fusion / MPL
到Hana
:
// In the old code, this used to receive a Fusion sequence.
// Now, it can be either a Hana sequence or a Fusion sequence.
template <typename Sequence>
void f(Sequence const& seq) {
hana::for_each(seq, [](auto const& element) {
std::cout << element << std::endl;
});
}
注意: 仅提供将其他库的数据类型用于
Hana
的适配器; 不提供适配器(将Hana
容器用于其他库)。
但是,使用外部适配器有几个陷阱。 例如,使用Hana
一段时间后,您可能习惯于使用正常的比较运算符比较Hana
元组,或者使用Hana
的integral_constants
进行算术。 但不保证这些操作符也被定义为外部适配器(并且通常它们不会)。 因此,你必须坚持Hana
提供的实现这些运算符的函数。 例如:
auto r = std::ratio<3, 4>{} + std::ratio<4, 5>{}; // error, the operator is not defined!
相反,您应该使用以下:
#include <boost/hana/ext/std/ratio.hpp>
#include <boost/hana/plus.hpp>
#include <ratio>
namespace hana = boost::hana;
auto r = hana::plus(std::ratio<3, 4>{}, std::ratio<4, 5>{});
但有时候,情况会更糟。 一些外部组件定义运算符,但它们不一定具有与来自Hana
的语义相同的语义。 例如,比较两个不同长度的std::tuple
会在使用operator ==
时产生错误:
std::make_tuple(1, 2, 3) == std::make_tuple(1, 2); // compiler error
另一方面,比较不同长度的Hana
元组将只返回一个错误的IntegralConstant
:
hana::make_tuple(1, 2, 3) == hana::make_tuple(1, 2); // hana::false_c
这是因为std::tuple
定义了自己的操作符,它们的语义与Hana
的操作符不同。 解决方案是坚持使用Hana
的命名函数,而不是使用运算符,当你知道你将需要使用其他库:
hana::equal(std::make_tuple(1, 2, 3), std::make_tuple(1, 2)); // hana::false_c
当使用外部适配器时,还应小心不要忘记包括正确的头文件。 例如,假设我想使用一个Boost.MPL
向量与Hana
。 我包括适当的头文件:
#include <boost/hana/ext/boost/mpl/vector.hpp> // bridge header
using Vector = mpl::vector<int, char, float>;
static_assert(hana::front(Vector{}) == hana::type_c<int>, "");
注意: 这些头文件的确切布局在关于头文件组织的部分中有说明。
然而,现在,假设我使用mpl::size
查询向量的大小,然后将其与某个值进行比较。 我也可以使用hana::length
,一切都会很好,但为了例子的缘故与我一起:
using Size = mpl::size<Vector>::type;
static_assert(hana::equal(Size{}, hana::int_c<3>), ""); // breaks!
这个断点的原因是mpl::size
返回一个MPL IntegralConstant
,Hana
无法知道这些,除非你包括正确的头文件。 因此,您应该执行以下操作:
#include <boost/hana/ext/boost/mpl/integral_c.hpp>
using Size = mpl::size<Vector>::type;
static_assert(hana::equal(Size{}, hana::int_c<3>), "");
在使用外部库时,你必须小心对待对你所操作的对象。 最后一个陷阱是关于外部库中的实现限制。 许多较旧的库对于可以使用它们创建的异构容器的最大大小是有限制的。 例如,不能创建包含FUSION_MAX_LIST_SIZE
个以上元素的Fusion
列表。 显然,这些限制是由Hana
继承的,例如,试图计算包含5
个元素的fusion::list
的排列(结果列表将包含120
个元素)将以可怕的方式失败:
auto list = fusion::make_list(1, 2, 3, 4, 5);
auto oh_jeez = hana::permutations(list); // probably won't make it
除了在本节中解释的陷阱,使用外部适配器应该像使用正常的Hana
容器一样简单。 当然,只要有可能,你应该试着坚持Hana
的容器,因为他们通常更友好的工作,并经常更优化。