template <class array="">constexpr auto count_nonzeros(Array a) noexcept { std::size_t count = 0; for (std::size_t i = 0; i < Array::size() && a.data[i]; ++i) ++ count; return count;}</class>
由于字段是按次序保存到 array 中的,所以在元素值为0时的 count 就是有效的元素个数。接下来我们来说说 detect _ fields _ count _ and _ type _ ids 的实现,这个 constexpr 函数将结构体中的数组类型 id 保存到 array 的 data 中。
detect_fields_count_and_type_ids<t>(types.data, std::make_index_sequence<sizeof(t)>{});</sizeof(t)></t>
detect _ fields _ count _ and _ type _ ids 的第一个参数为定长数组 array <std::size _ t, sizeof(T)> 的 data,第二个参数是一个 std::index _ sequence 整形序列。detect _ fields _ count _ and _ type _ ids 具体实现代码如下:
template <class t,="" std::size_t="" i0,="" std::size_t...="" i="">constexpr auto detect_fields_count_and_type_ids(std::size_t* types, std::index_sequence<i0, i...="">) noexcept-> decltype( type_to_array_of_type_ids<t, i0,="" i...="">(types) ){ return type_to_array_of_type_ids<t, i0,="" i...="">(types);}template <class t,="" std::size_t...="" i="">constexpr T detect_fields_count_and_type_ids(std::size_t* types, std::index_sequence<i...>) noexcept { return detect_fields_count_and_type_ids<t>(types, std::make_index_sequence<sizeof...(i) -="" 1="">{});}template <class t="">constexpr T detect_fields_count_and_type_ids(std::size_t*, std::index_sequence<>) noexcept { static_assert(!!sizeof(T), "Failed for unknown reason"); return T{};}</class></sizeof...(i)></t></i...></class></t,></t,></i0,></class>
上面的代码是为了将 index _ sequence 展开为 0,1,2..., sizeof(T) 序列,得到这个序列以后,再读取 type _ to _ array _ of _ type _ ids 函数实现结构体中的字段类别 id 保存到 array 中。
在讲 type _ to _ array _ of _ type _ ids 函数之前我们先看一下辅助结构体 ubiq。保存 pod 字段类别 id 实际上是由辅助结构体 ubiq 实现的,它的实现如下:
template <std::size_t i="">struct ubiq { std::size_t* ref_; template <class type=""> constexpr operator Type() const noexcept { ref_[I] = type_to_id(identity<type>{}); return Type{}; }};</type></class></std::size_t>
这个结构体比较特殊,我们先把它简化一下。
struct ubiq { template <class type=""> constexpr operator Type() const { return Type{}; };};</class>

这个结构体的特殊之处在于它可以拿来构造任意 pod 类型,比如 int、char、double 等类别。
int i = ubiq{};double d = ubiq{};char c = ubiq{};
因为 ubiq 构造函数所必须的类别由编译器自动判断起来,所以它能构造任意 pod 类型。通过 ubiq 结构体获取了应该构造的类型以后,我们还必须将这个类别转换为 id 按次序保存到定长数组中。
template <std::size_t i="">struct ubiq { std::size_t* ref_; template <class type=""> constexpr operator Type() const noexcept { ref_[I] = type_to_id(identity<type>{}); return Type{}; }};</type></class></std::size_t>
上面的代码中先将编译器推导出来的类别转换为 id,然后保存到链表数组为 I 的位置。
再回头看 type _ to _ array _ of _ type _ ids 函数。
template <class t,="" std::size_t...="" i="">constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept -> decltype(T{ ubiq<i>{types}... }) { return T{ ubiq<i>{types}... };}</i></i></class>
type _ to _ array _ of _ type _ ids 有两个模版参数,第一个 T 是 pod 结构体的类别,第二个 size _ t...为0到 sizeof(T) 的整形序列,函数的入参为 size _ t*,它实际上是 array<std::size_t, sizeof(T)> 的 data,用来保存 pod 字段类别 id。
保存字段类别的关键代码是这一行:T{ ubiq〈I〉{types}... },这里利用了 pod 类型的构造函数,通过 initializer _ list 构造,编译器会将 T 的字段类别归纳出来,并通过 ubiq 将字段类别转换为 id 保存到变量中。这个就是 magic _ get 中的 magic。
将 pod 结构体字段 id 保存到变量中以后,接下来就应该将变量中的 id 列表转换为 tuple 了。
pod 字段 id 序列转化为 tuple 的详细做法分为两步:
下面是详细的实现代码:
template <std::size_t i,="" class="" t,="" std::size_t="" n="">constexpr const T& get(const array<t,n>& a) noexcept { return a.data[I];}template <class t,="" std::size_t...="" i="">constexpr auto array_of_type_ids_to_index_sequence(std::index_sequence<i...>) noexcept { constexpr auto a = array_of_type_ids<t>(); return std::index_sequence< get<i>(a)...>{};}</i></t></i...></class></t,n></std::size_t>
get 是返回函数中某个键值位置的元素值,即类型 id,返回的 id 放入 std::index _ sequence 中,接着就是通过 index _ sequence 将 index _ sequence 中的 id 转换为 type,组成一个 tuple。
template <std::size_t... i="">constexpr auto as_tuple_impl(std::index_sequence<i...>) noexcept { return std::tuple< decltype( id_to_type(std::integral_constant<std::size_t, i="">{}) )... >{};}template <class t="">constexpr auto as_tuple() noexcept { static_assert(std::is_pod<t>::value, "Not applyable"); constexpr auto res = as_tuple_impl( array_of_type_ids_to_index_sequence<t>( std::make_index_sequence< decltype(array_of_type_ids<t>())::size() >() ) ); static_assert(sizeof(res) == sizeof(T), "sizes check failed"); static_assert( std::alignment_of<decltype(res)>::value == std::alignment_of<t>::value, "alignment check failed" ); return res;}</t></decltype(res)></t></t></t></class></std::size_t,></i...></std::size_t...>
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-129594-2.html
送项目拉动它们的经济
台湾执政者也是明白之人