|
1 | 1 | #include<type_traits>
|
2 |
| -#include<iostream> |
3 |
| -#include<array> |
4 |
| -#include<numeric> |
5 | 2 | #include<tuple>
|
6 |
| - |
7 |
| -//需要C++20以上 |
8 |
| -//这个程序的原理是用std::is_constructible猜测类的成员类型 |
9 |
| -//然后使用偏移量来访问类的数据成员 |
10 |
| -namespace my_utilities |
| 3 | +#include<iostream> |
| 4 | +namespace possibilities |
11 | 5 | {
|
12 |
| - struct inits |
| 6 | + //需要C++20以上 |
| 7 | + //测试了MSVC latest, clang16, gcc13 |
| 8 | + //原理是用std::is_constructible猜测类的成员类型 |
| 9 | + //注意:需要给出类中可能出现的所有类型,但是不一定是精确的,可以多猜点,但是不能缺少,缺少会编译不过 |
| 10 | + namespace possibilities_utilities |
13 | 11 | {
|
14 |
| - template<class T> operator T(); |
15 |
| - }; |
| 12 | + struct inits |
| 13 | + { |
| 14 | + template<class T> operator T(); |
| 15 | + }; |
| 16 | + //这个类型用来试探某种类型是不是类的第N个成员类型 |
| 17 | + //由于std::is_constructible隐式转换也会true,所以这里禁止隐式转换以求结果精确 |
| 18 | + template<class T> struct convert_forbid |
| 19 | + { |
| 20 | + using type = T; |
| 21 | + template<class U,class En = std::enable_if_t<std::is_same_v<T, U>>> operator U(); |
| 22 | + }; |
| 23 | + //计算成员数量,生成构造列表 |
| 24 | + template<bool, class T, class construct_list, std::size_t cnt> struct count_size{}; |
| 25 | + template<class T, template<class...> class construct_list, std::size_t cnt, class ...types> |
| 26 | + struct count_size<true, T, construct_list<types...>, cnt> |
| 27 | + { |
| 28 | + static constexpr std::size_t value = cnt; |
| 29 | + using CTL = construct_list<T, types...>; |
| 30 | + }; |
| 31 | + template<class T, template<class ...> class construct_list, std::size_t cnt, class First, class ...rest> |
| 32 | + struct count_size<false, T, construct_list<First, rest...>, cnt> |
| 33 | + { |
| 34 | + using next = count_size<std::is_constructible_v<T, First, rest...>,T, std::conditional_t< |
| 35 | + std::is_constructible_v<T, First, rest...>, construct_list<First, rest...>, construct_list<rest...>>, |
| 36 | + (std::is_constructible_v<T, First, rest...> ? cnt : cnt - 1)>; |
| 37 | + static constexpr std::size_t value =next::value; |
| 38 | + using CTL = typename next::CTL; |
| 39 | + }; |
| 40 | + //工具类,用于替换构造列表中的元素 |
| 41 | + template<std::size_t N, class pre, class bck, class T> struct replace_at{}; |
| 42 | + template<std::size_t N, template<class...> class pre, template<class...> class bck, class RP, class bck_first, class ...preargs, class... bckargs> |
| 43 | + struct replace_at<N, pre<preargs...>, bck<bck_first, bckargs...>, RP> |
| 44 | + { |
| 45 | + using type = typename replace_at<N - 1, pre<preargs..., bck_first>, bck<bckargs...>, RP>::type; |
| 46 | + }; |
16 | 47 |
|
17 |
| - //这个类型用来试探某种类型是不是类的第N个成员类型 |
18 |
| - //由于std::is_constructible隐式转换也会true,所以这里禁止隐式转换 |
19 |
| - //以求结果精确 |
20 |
| - template<class T> struct convert_forbid |
21 |
| - { |
22 |
| - using type = T; |
23 |
| - template< |
24 |
| - class U, |
25 |
| - class En = std::enable_if_t<std::is_same_v<T, U>> |
26 |
| - > operator U(); |
27 |
| - }; |
28 |
| - //计算成员数量 |
29 |
| - template<bool, class T, class construct_list, size_t cnt> struct count_size |
30 |
| - { |
31 |
| - static constexpr size_t value = cnt; |
32 |
| - }; |
33 |
| - template<class T, template<class ...> class construct_list, size_t cnt, class First, class ...rest> |
34 |
| - struct count_size<false, T, construct_list<First, rest...>, cnt> |
35 |
| - { |
36 |
| - static constexpr size_t value = |
37 |
| - count_size< |
38 |
| - std::is_constructible_v<T, First, rest...>, |
39 |
| - T, |
40 |
| - construct_list<rest...>, |
41 |
| - (std::is_constructible_v<T, First, rest...> ? cnt : cnt - 1)> |
42 |
| - ::value; |
43 |
| - }; |
44 |
| - //工具类,选择类型分支 |
45 |
| - //本来我想用type_traits里面的,不熟悉就没用 |
46 |
| - template<bool cond, class A, class B> struct select_impl |
47 |
| - { |
48 |
| - using type = A; |
49 |
| - }; |
| 48 | + template<template<class...> class pre, template<class...> class bck, class RP, class bck_first, class ...preargs, class... bckargs> |
| 49 | + struct replace_at<0, pre<preargs...>, bck<bck_first, bckargs...>, RP> |
| 50 | + { |
| 51 | + using type = pre<preargs..., RP, bckargs...>; |
| 52 | + }; |
| 53 | + |
| 54 | + template<class TL, template<class...> class Name> struct as_ {}; |
| 55 | + template<template<class...>class TL, template<class...>class Name, class ...Args> struct as_<TL<Args...>, Name> |
| 56 | + { using type = Name<Args...>; }; |
| 57 | + //在列表中选择元素 |
| 58 | + template<std::size_t N, class TL> struct select_element { using type = std::tuple_element_t<N, typename as_<TL, std::tuple>::type>; }; |
| 59 | + } |
| 60 | + using namespace possibilities_utilities; |
| 61 | + |
| 62 | + template<class ...> struct tl {}; |
50 | 63 |
|
51 |
| - template<class A, class B> struct select_impl<false, A, B> |
| 64 | + template<class T> using count_size_type = count_size<false, std::decay_t<T>, tl<inits, inits, inits, inits, inits, inits, inits, inits, inits, inits>, 10>; |
| 65 | + template<class T> constexpr std::size_t size() { |
| 66 | + return count_size_type<T>::value; |
| 67 | + } |
| 68 | + //工具类,测试T的N个成员是否为Mem_type |
| 69 | + template<std::size_t N, class T, class Mem_type> struct is_constructible_at |
52 | 70 | {
|
53 |
| - using type = B; |
54 |
| - }; |
55 |
| - template<bool b, class A, class B> using select_branch = typename select_impl<b, A, B>::type; |
| 71 | + using construct_list = typename count_size_type<T>::CTL; |
| 72 | + using chk_constructible = typename replace_at<N + 1, tl<>, construct_list, convert_forbid<Mem_type>>::type; |
| 73 | + using constructible_type = typename as_<chk_constructible, std::is_constructible>::type; |
| 74 | + static constexpr bool value = constructible_type::value; |
56 | 75 |
|
57 |
| - template<class T, class TL> struct add_front {}; |
58 |
| - template<class T, template<class...> class TL, class...Args> struct add_front<T, TL<Args...>> |
| 76 | + }; |
| 77 | + //工具类,用一个列表mem_type_list逐个测试is_constructilbe_at,得到T的第N个成员的类型 |
| 78 | + template<bool constructible_, std::size_t N, class T, class mem_type_list> struct constructible_at_try {}; |
| 79 | + template<bool constructible_, std::size_t N, class T, template<class...> class mem_type_list, class first, class ...Args> |
| 80 | + struct constructible_at_try<constructible_, N, T, mem_type_list<first, Args...>> |
59 | 81 | {
|
60 |
| - using type = TL<T, Args...>; |
| 82 | + static constexpr bool cstible = is_constructible_at<N, T, first>::value; |
| 83 | + using type = typename constructible_at_try<cstible, N, T, |
| 84 | + std::conditional_t<cstible, mem_type_list<first, Args...>, mem_type_list<Args...>>>::type; |
61 | 85 | };
|
62 | 86 |
|
63 |
| - template<size_t N, class T, class TL> struct gen_list |
64 |
| - {}; |
65 |
| - |
66 |
| - template<class T, template<class...> class TL, class ...Args> struct gen_list<0, T, TL<Args...>> |
| 87 | + template<std::size_t N, class T, template<class...> class mem_type_list, class first, class ...Args> |
| 88 | + struct constructible_at_try<true, N, T, mem_type_list<first, Args...>> {using type = first;}; |
| 89 | + //工具类,生成成员列表 |
| 90 | + template<std::size_t N, class T, class TL, class saved> struct make_construct_list {}; |
| 91 | + template<class T, template<class...> class TL, template<class...> class saved, class ...Args, class ...savedArgs> |
| 92 | + struct make_construct_list<0, T, TL<Args...>, saved<savedArgs...>> |
67 | 93 | {
|
68 |
| - using type = TL<Args...>; |
| 94 | + using current_type = typename constructible_at_try<false, 0, T, TL<Args...>>::type; |
| 95 | + using type = saved<current_type, savedArgs...>; |
69 | 96 | };
|
70 |
| - |
71 |
| - template<size_t N, template<class...> class TL, class T, class ...Args> struct gen_list<N, T, TL<Args...>> |
| 97 | + template<std::size_t N, class T, template<class...> class saved, class TL, class ...Args> struct make_construct_list<N, T, TL, saved<Args...>> |
72 | 98 | {
|
73 |
| - using type = typename gen_list<N - 1, T, TL<Args..., T>>::type; |
| 99 | + using current_type = typename constructible_at_try<false, N, T, TL>::type; |
| 100 | + using type = typename make_construct_list<N - 1, T, TL, saved<current_type, Args...>>::type; |
74 | 101 | };
|
75 | 102 |
|
| 103 | + template<class T, class Poss> using possibility = typename make_construct_list<possibilities::size<T>() - 1, T, Poss, tl<>>::type; |
| 104 | +} |
76 | 105 |
|
77 |
| - |
78 |
| - template<size_t N, class pre, class bck, class T> struct replace_at |
| 106 | +namespace offset_pointer{ |
| 107 | + //offset_ptr模拟成员在结构体中的分布, advance:跨越一个指定的size的成员, forward_offset:寻找下一个成员的首地址 |
| 108 | + template<std::size_t pack_size, std::size_t layer_offset, std::size_t offset> struct offset_ptr |
79 | 109 | {
|
| 110 | + static_assert(pack_size <= 8, "An alignment size exceeds 8 is not tested!"); |
| 111 | + static constexpr std::size_t layer = layer_offset;//alignment layer as base |
| 112 | + static constexpr std::size_t value = offset;//当前层偏移指针 |
| 113 | + static constexpr std::size_t half_pack = pack_size / 2;//层的半对齐 |
| 114 | + //工具:移动到下一内存对齐的层, 层偏移指针置零 |
| 115 | + template<std::size_t N> using advance_layer = offset_ptr<pack_size, layer + N, 0>; |
| 116 | + //当forward offset + 当前层偏移超出或等于内存对齐的值 |
| 117 | + //假如forward offset+value==pack_size, 或则当前层偏移为0时,成员会存在当前层, 移动 size/pack_size + 1层, |
| 118 | + //否则当size%pack_size == 0, size/pack_size + 2层,因为它会被放在下一层 |
| 119 | + //否则当size%pack_size != 0, size/pack_size + 3层(暂时没见过这种情况,数组可能会出现,但是这个类不让使用数组) |
| 120 | + template<bool offset_overflow_pack, std::size_t forward_offset> struct advance_impl |
| 121 | + { |
| 122 | + static constexpr std::size_t forward_base = forward_offset / pack_size; |
| 123 | + static constexpr bool has_rest = static_cast<bool>(forward_offset % pack_size); |
| 124 | + static constexpr std::size_t forward_base_fixed = has_rest ? forward_base + 1 : forward_base; |
| 125 | + using type = advance_layer<(((forward_offset + value) == 8) ? 0 : (value == 0 ? 0 : 1)) + forward_base_fixed>; |
| 126 | + }; |
| 127 | + //当forward offset + 当前层偏移小于内存对齐的值,位移不超过当前层 |
| 128 | + //但是当forward offset超过半对齐,成员就会存储在后一半层, 否则直接移动forward offset |
| 129 | + template<std::size_t forward_offset> struct advance_impl<false, forward_offset> |
| 130 | + { |
| 131 | + using type = offset_ptr<pack_size, layer, (value + forward_offset >= half_pack) ? pack_size : value + forward_offset>; |
| 132 | + }; |
| 133 | + //工具:使指针越过一个成员的位置 |
| 134 | + template<std::size_t forward_offset> using advance = typename advance_impl<((value + forward_offset) >= pack_size), forward_offset>::type; |
| 135 | + //探索指针,用于寻找下一个成员的首地址,只在get中使用 |
| 136 | + //枚举了给定的指针是否超过半对齐,内存对齐的情况 |
| 137 | + template<std::size_t forward_size> struct forward_impl |
| 138 | + { |
| 139 | + using type = std::conditional_t<(forward_size >= pack_size), |
| 140 | + advance_layer<(value == 0)?0:1>, offset_ptr<pack_size, layer, |
| 141 | + ((forward_size >= half_pack) ? ((value == 0) ? 0 : half_pack) : 0) >>; |
| 142 | + }; |
| 143 | + template<std::size_t forward_size> using forward_offset = typename forward_impl<forward_size>::type; |
| 144 | + //基于当前的层偏移,使用探索指针寻找给定的类型的首地址 |
| 145 | + template<class T, class type> static type& get(T* ptr) |
| 146 | + { |
| 147 | + static_assert(!std::is_array_v<type>, "calculating size of an array is not tested!"); |
| 148 | + return *(reinterpret_cast<type*>( |
| 149 | + reinterpret_cast<unsigned char*>(ptr) + |
| 150 | + ( |
| 151 | + forward_offset<sizeof(type)>::layer * pack_size + |
| 152 | + forward_offset<sizeof(type)>::value |
| 153 | + ))); |
| 154 | + } |
80 | 155 | };
|
81 |
| - |
82 |
| - template<size_t N, template<class...> class pre, template<class...> class bck, class RP, class bck_first, class ...preargs, class... bckargs> |
83 |
| - struct replace_at<N, pre<preargs...>, bck<bck_first, bckargs...>, RP> |
| 156 | + //递归迭代,实现类似std::get的方法 |
| 157 | + template<std::size_t N, class offset_pointer, class TL> struct offset_iter {}; |
| 158 | + template<std::size_t N, class offset_pointer, template<class ...> class TL, class first, class ...rest> |
| 159 | + struct offset_iter<N, offset_pointer, TL<first, rest...>> |
84 | 160 | {
|
85 |
| - using type = typename replace_at<N - 1, pre<preargs..., bck_first>, bck<bckargs...>, RP>::type; |
86 |
| - }; |
| 161 | + using recurse_type = offset_iter<N - 1, typename offset_pointer::template advance<sizeof(first)>, TL<rest...>>; |
| 162 | + using iter_type = typename recurse_type::iter_type; |
| 163 | + using type = typename recurse_type::type; |
87 | 164 |
|
88 |
| - template<template<class...> class pre, template<class...> class bck, class RP, class bck_first, class ...preargs, class... bckargs> |
89 |
| - struct replace_at<0, pre<preargs...>, bck<bck_first, bckargs...>, RP> |
90 |
| - { |
91 |
| - using type = pre<preargs..., RP, bckargs...>; |
92 | 165 | };
|
93 |
| - |
94 |
| - template<class TL, template<class...> class Name> struct as_ {}; |
95 |
| - template<template<class...>class TL, template<class...>class Name, class ...Args> struct as_<TL<Args...>, Name> |
| 166 | + template<class offset_pointer, template<class...> class TL, class first, class ...rest> |
| 167 | + struct offset_iter<0, offset_pointer, TL<first, rest...>> |
96 | 168 | {
|
97 |
| - using type = Name<Args...>; |
| 169 | + using type = first; |
| 170 | + using iter_type = offset_pointer; |
98 | 171 | };
|
99 |
| - template<class ...> struct tl {}; |
100 |
| - |
101 |
| - //在列表种选择元素 |
102 |
| - //懒得写了,骗一下这个tuple_element_t |
103 |
| - template<size_t N, class TL> struct select_element { using type = std::tuple_element_t<N, typename as_<TL, std::tuple>::type>; }; |
104 |
| - |
105 |
| -} |
106 |
| -using namespace my_utilities; |
107 |
| - |
108 |
| - |
109 |
| -template<class T> constexpr size_t size() |
110 |
| -{ |
111 |
| - return count_size<false, std::decay_t<T>, tl<inits, inits, inits, inits, inits, inits, inits, inits, inits, inits>, 10>::value; |
112 |
| -} |
113 |
| - |
114 |
| - |
115 |
| -//工具类,测试T的N个成员是否为Mem_type |
116 |
| -template<size_t N, class T, class Mem_type> struct is_constructible_at |
117 |
| -{ |
118 |
| - using construct_list = typename gen_list<size<T>(), inits, tl<T>>::type; |
119 |
| - using chk_constructible = typename replace_at<N + 1, tl<>, construct_list, convert_forbid<Mem_type>>::type; |
120 |
| - |
121 |
| - using constructible_type = typename as_<chk_constructible, std::is_constructible>::type; |
122 |
| - static constexpr bool value = constructible_type::value; |
123 |
| - |
124 |
| -}; |
125 |
| -//工具类,用一个列表mem_type_list逐个测试is_constructilbe_at,得到T的第N个成员的类型 |
126 |
| -template<bool constructible_, size_t N, class T, class mem_type_list> struct constructible_at_try {}; |
127 |
| -template<bool constructible_, size_t N, class T, template<class...> class mem_type_list, class first, class ...Args> |
128 |
| -struct constructible_at_try<constructible_, N, T, mem_type_list<first, Args...>> |
129 |
| -{ |
130 |
| - static constexpr bool cstible = is_constructible_at<N, T, first>::value; |
131 |
| - using type = typename constructible_at_try<cstible, |
132 |
| - N, |
133 |
| - T, |
134 |
| - select_branch<cstible, mem_type_list<first, Args...>, mem_type_list<Args...> |
135 |
| - > |
136 |
| - >::type; |
137 |
| -}; |
138 |
| - |
139 |
| -template<size_t N, class T, template<class...> class mem_type_list, class first, class ...Args> struct constructible_at_try<true, N, T, mem_type_list<first, Args...>> |
140 |
| -{ |
141 |
| - using type = first; |
142 |
| -}; |
143 |
| -//工具类,生成成员列表 |
144 |
| -template<size_t N, class T, class TL, class saved> struct make_construct_list |
145 |
| -{}; |
146 |
| -template<class T, template<class...> class TL, template<class...> class saved, class ...Args, class ...savedArgs> struct make_construct_list<0, T, TL<Args...>, saved<savedArgs...>> |
147 |
| -{ |
148 |
| - using current_type = typename constructible_at_try<false, 0, T, TL<Args...>>::type; |
149 |
| - using type = typename add_front<current_type, saved<savedArgs...>>::type; |
150 |
| -}; |
151 |
| -template<size_t N, class T, template<class...> class saved, class TL, class ...Args> struct make_construct_list<N, T, TL, saved<Args...>> |
152 |
| -{ |
153 |
| - using current_type = typename constructible_at_try<false, N, T, TL>::type; |
154 |
| - using type = typename make_construct_list<N - 1, T, TL, saved<current_type, Args...>>::type; |
155 |
| -}; |
156 |
| - |
157 |
| - |
158 |
| -//计算偏移 |
159 |
| -template<size_t pack_size, template<class...> class TL, class ...Typs> constexpr auto make_offset_list(TL<Typs...>) |
160 |
| -{ |
161 |
| - return std::array{ (sizeof(Typs) % pack_size ? sizeof(Typs) / pack_size * pack_size + pack_size : sizeof(Typs))... }; |
162 |
| -} |
163 |
| - |
164 |
| - |
165 |
| -template<size_t pack_size, class T, class possibilities> class offset_pointer |
166 |
| -{ |
167 |
| - using construct_list = typename make_construct_list<size<T>() - 1, T, possibilities, tl<>>::type; |
168 |
| -public: |
169 |
| - offset_pointer(T* a) noexcept : baseptr(reinterpret_cast<unsigned char*>(a)) {} |
170 |
| - template<size_t I> typename select_element<I, construct_list>::type get() const |
| 172 | + //封装成函数 |
| 173 | + template<std::size_t I, class CTL, class T> auto& get_member(T* x) |
171 | 174 | {
|
172 |
| - if constexpr (I == 0) { |
173 |
| - return *(reinterpret_cast<std::add_pointer_t<typename select_element<0, construct_list>::type>>(baseptr)); |
174 |
| - } |
175 |
| - else |
176 |
| - { |
177 |
| - return *( |
178 |
| - reinterpret_cast<std::add_pointer_t<typename select_element<I, construct_list>::type>>( |
179 |
| - baseptr + std::accumulate(member_offset.begin() + 1, member_offset.begin() + 1 + I, 0) |
180 |
| - ) |
181 |
| - ); |
182 |
| - } |
| 175 | + using types_iter = offset_iter<I, offset_ptr<alignof(T), 0, 0>, CTL>; |
| 176 | + return types_iter::iter_type::template get<T, typename types_iter::type>(x); |
183 | 177 | }
|
184 |
| -private: |
185 |
| - unsigned char* baseptr; |
186 |
| - std::array<size_t, size<T>()> |
187 |
| - member_offset{ |
188 |
| - make_offset_list<pack_size>(typename make_construct_list<size<T>() - 1, T, possibilities, tl<>>::type()) |
189 |
| - }; |
190 |
| -}; |
| 178 | +} |
| 179 | + |
| 180 | +using namespace possibilities; |
| 181 | +using namespace offset_pointer; |
| 182 | +using possible = tl<int, std::string, double, char>; |
191 | 183 |
|
192 |
| -//理论上可以算内存对齐,但是已经太长了,不想写那个了 |
193 |
| -template<class T, class F, size_t ...I> void for_each_member_impl(T&& t, F&& f, std::index_sequence<I...>) |
| 184 | +template<class T, class F, size_t ...I> constexpr void for_each_member_impl(T&& x, F&& f, std::index_sequence<I...>) |
194 | 185 | {
|
195 |
| - //有点上帝视角了,因为已经看到了所有的数据类型 |
196 |
| - using possible_types = tl<int, std::string, double>; |
197 |
| - offset_pointer<alignof(T), T, possible_types> op{ &t }; |
198 |
| - (f(op.template get<I>()), ...); |
| 186 | + ((f(get_member<I, possibility<T, possible>>(&x))), ...); |
199 | 187 | }
|
200 | 188 |
|
201 |
| -template<class T, class F> constexpr void for_each_member(T&& t, F&& f) |
| 189 | +template<class T, class F> constexpr void for_each_member(T&& x, F&& f) |
202 | 190 | {
|
203 |
| - for_each_member_impl(std::move(t), std::move(f), std::make_index_sequence<size<T>()>{}); |
| 191 | + for_each_member_impl(std::move(x), std::move(f), std::make_index_sequence<size<T>()>{}); |
204 | 192 | }
|
205 | 193 |
|
206 | 194 | int main() {
|
|
0 commit comments