0. Boost.Hana.members
members是定义在namespace boost::hana下的一个变量,拥有类型members_t。
member_t内重载了运算符<Object> operator(Object&&),接收特定类型的结构体,并返回hana::tuple<...Xn>,利用该元组,可以访问结构体的每个成员。
且该结构体内必须含有且在BOOST_HANA_DEFINE_STRUCT中的成员才能被members的反射机制所利用。
例如:
struct A {
int b;
BOOST_HANA_DEFINE_STRUCT(A,
(int, a),
(double,d))
};
那么members就可以反射到a和d,但是无法反射获取b。
1. 问题阐述
在使用hana::members去反射访问结构体成员时,出现了如下情况
已知operator()返回元组类型,因此,像这样访问元组元素是可行的:
auto element0 = boost::hana::at_c<0>(boost::hana::members(A{}));
同时我们注意到。hana::tuple重载了operator[]用以访问元组元素,但是当我们自然地写出这样的语句时:
auto mems = boost::hana::members(A{});
auto element0 = mems[0];
却无法编译通过,且报错信息如下:
error: static assertion failed due to requirement 'hana::IntegralConstant<int>::value': hana::at(xs, n) requires 'n' to be an IntegralConstant
2. 尝试解决
我们查看源码发现,在at_t::opeartor()的定义中有着:
static_assert(hana::IntegralConstant<N>::value,
"hana::at(xs, n) requires 'n' to be an IntegralConstant");
到这里,我们需要再弄清楚hana::IntegralConstant<N>是什么
再次查看源码:
namespace detail {
template <typename C, typename Tag = typename tag_of<C>::type>
struct integral_constant_dispatch
: hana::integral_constant<bool,
hana::IntegralConstant<Tag>::value
>
{ };
template <typename C>
struct integral_constant_dispatch<C, C>
: hana::integral_constant<bool, false>
{ };
}
template <typename C>
struct IntegralConstant
: detail::integral_constant_dispatch<C>
{ };
我们大致能够看出,如果integral_constant_dispatch的C和Tag类型不同,那么integral_constant::value就是true,否则,就是false。
再查看tag_of的模板(这里不再放出)和其特化,我们发现,非特化情况Tag与类型C相等,或者&、&&、const、volatile和const volatile类型没有type的定义。但其对std::integral_constant具有特化,使得Tag与类型C不相等。
于是我们可以这样传参:
boost::hana::members(A{})[std::integral_constant<int, 1>{}];
编译通过,解决问题。
当然,使用boost.hana.integral_constant依然可以,因为其继承了std::integral
不过,在boost::hana中已经定义了hana::integral_constant类型的变量int_c,我们可以直接使用int_c<N>来传参。