@@ -85,36 +85,39 @@ struct BinaryExpr {
8585 }
8686 }
8787
88- constexpr decltype(auto) eval(auto const& args) const {
88+ template <typename T>
89+ constexpr decltype(auto) eval(T&& args) const {
8990 auto descend = [&](auto&& obj) {
9091 constexpr auto evaluatable = requires {
91- { obj.eval(args) } -> _impl::is_non_void;
92+ { obj.eval(std::forward<T>( args) ) } -> _impl::is_non_void;
9293 };
9394
9495 if constexpr (evaluatable) {
95- return obj.eval(args);
96+ return obj.eval(std::forward<T>( args) );
9697 } else {
9798 return obj;
9899 }
99100 };
100101
101- return eval_operator(descend(rhs) , descend(lhs ));
102+ return eval_operator(descend(std::forward_like<T>(lhs)) , descend(std::forward_like<T>(rhs) ));
102103 }
103104
104- constexpr auto eval_verbose(auto const& args, std::vector<std::string>& failed_terms) const {
105+ template <typename T>
106+ constexpr auto eval_verbose(T&& args, std::vector<std::string>& failed_terms) const {
105107 auto descend = [&](auto&& obj) {
106108 constexpr auto evaluatable = requires {
107- { obj.eval_verbose(args, failed_terms) } -> _impl::is_non_void;
109+ { obj.eval_verbose(std::forward<T>( args) , failed_terms) } -> _impl::is_non_void;
108110 };
109111
110112 if constexpr (evaluatable) {
111- return obj.eval_verbose(args, failed_terms);
113+ return obj.eval_verbose(std::forward<T>( args) , failed_terms);
112114 } else {
113115 return obj;
114116 }
115117 };
116118
117- auto result = eval_operator(descend(rhs), descend(lhs));
119+ auto result =
120+ eval_operator(descend(std::forward_like<T>(lhs)), descend(std::forward_like<T>(rhs)));
118121 if (!result) {
119122 failed_terms.push_back(to_string(args));
120123 }
@@ -162,70 +165,72 @@ struct BinaryExpr {
162165 }
163166 }
164167
165- static constexpr decltype(auto) eval_operator(auto lhs, auto rhs) {
168+ template <typename T2, typename T1>
169+ static constexpr decltype(auto) eval_operator(T1&& rhs, T2&& lhs) {
170+ // TODO args are flipped - why?
166171 using enum std::meta::operators;
167172 /* */ if constexpr (OP == op_plus) {
168- return lhs + rhs;
173+ return std::forward<T1>( lhs) + std::forward<T2>( rhs) ;
169174 } else if constexpr (OP == op_minus) {
170- return lhs - rhs;
175+ return std::forward<T1>( lhs) - std::forward<T2>( rhs) ;
171176 } else if constexpr (OP == op_star) {
172- return lhs * rhs;
177+ return std::forward<T1>( lhs) * std::forward<T2>( rhs) ;
173178 } else if constexpr (OP == op_slash) {
174- return lhs / rhs;
179+ return std::forward<T1>( lhs) / std::forward<T2>( rhs) ;
175180 } else if constexpr (OP == op_percent) {
176- return lhs % rhs;
181+ return std::forward<T1>( lhs) % std::forward<T2>( rhs) ;
177182 } else if constexpr (OP == op_caret) {
178- return lhs ^ rhs;
183+ return std::forward<T1>( lhs) ^ std::forward<T2>( rhs) ;
179184 } else if constexpr (OP == op_ampersand) {
180- return lhs & rhs;
185+ return std::forward<T1>( lhs) & std::forward<T2>( rhs) ;
181186 } else if constexpr (OP == op_pipe) {
182- return lhs | rhs;
187+ return std::forward<T1>( lhs) | std::forward<T2>( rhs) ;
183188 } else if constexpr (OP == op_equals) {
184- return lhs = rhs;
189+ return std::forward<T1>( lhs) = std::forward<T2>( rhs) ;
185190 } else if constexpr (OP == op_plus_equals) {
186- return lhs += rhs;
191+ return std::forward<T1>( lhs) += std::forward<T2>( rhs) ;
187192 } else if constexpr (OP == op_minus_equals) {
188- return lhs -= rhs;
193+ return std::forward<T1>( lhs) -= std::forward<T2>( rhs) ;
189194 } else if constexpr (OP == op_star_equals) {
190- return lhs *= rhs;
195+ return std::forward<T1>( lhs) *= std::forward<T2>( rhs) ;
191196 } else if constexpr (OP == op_slash_equals) {
192- return lhs /= rhs;
197+ return std::forward<T1>( lhs) /= std::forward<T2>( rhs) ;
193198 } else if constexpr (OP == op_percent_equals) {
194- return lhs %= rhs;
199+ return std::forward<T1>( lhs) %= std::forward<T2>( rhs) ;
195200 } else if constexpr (OP == op_caret_equals) {
196- return lhs ^= rhs;
201+ return std::forward<T1>( lhs) ^= std::forward<T2>( rhs) ;
197202 } else if constexpr (OP == op_ampersand_equals) {
198- return lhs &= rhs;
203+ return std::forward<T1>( lhs) &= std::forward<T2>( rhs) ;
199204 } else if constexpr (OP == op_pipe_equals) {
200- return lhs |= rhs;
205+ return std::forward<T1>( lhs) |= std::forward<T2>( rhs) ;
201206 } else if constexpr (OP == op_equals_equals) {
202- return lhs == rhs;
207+ return std::forward<T1>( lhs) == std::forward<T2>( rhs) ;
203208 } else if constexpr (OP == op_exclamation_equals) {
204- return lhs != rhs;
209+ return std::forward<T1>( lhs) != std::forward<T2>( rhs) ;
205210 } else if constexpr (OP == op_less) {
206- return lhs < rhs;
211+ return std::forward<T1>( lhs) < std::forward<T2>( rhs) ;
207212 } else if constexpr (OP == op_greater) {
208- return lhs > rhs;
213+ return std::forward<T1>( lhs) > std::forward<T2>( rhs) ;
209214 } else if constexpr (OP == op_less_equals) {
210- return lhs <= rhs;
215+ return std::forward<T1>( lhs) <= std::forward<T2>( rhs) ;
211216 } else if constexpr (OP == op_greater_equals) {
212- return lhs >= rhs;
217+ return std::forward<T1>( lhs) >= std::forward<T2>( rhs) ;
213218 } else if constexpr (OP == op_spaceship) {
214- return lhs <=> rhs;
219+ return std::forward<T1>( lhs) <=> std::forward<T2>( rhs) ;
215220 } else if constexpr (OP == op_ampersand_ampersand) {
216- return lhs && rhs;
221+ return std::forward<T1>( lhs) && std::forward<T2>( rhs) ;
217222 } else if constexpr (OP == op_pipe_pipe) {
218- return lhs || rhs;
223+ return std::forward<T1>( lhs) || std::forward<T2>( rhs) ;
219224 } else if constexpr (OP == op_less_less) {
220- return lhs << rhs;
225+ return std::forward<T1>( lhs) << std::forward<T2>( rhs) ;
221226 } else if constexpr (OP == op_greater_greater) {
222- return lhs >> rhs;
227+ return std::forward<T1>( lhs) >> std::forward<T2>( rhs) ;
223228 } else if constexpr (OP == op_less_less_equals) {
224- return lhs <<= rhs;
229+ return std::forward<T1>( lhs) <<= std::forward<T2>( rhs) ;
225230 } else if constexpr (OP == op_greater_greater_equals) {
226- return lhs >>= rhs;
231+ return std::forward<T1>( lhs) >>= std::forward<T2>( rhs) ;
227232 } else if constexpr (OP == op_comma) {
228- return lhs, rhs;
233+ return std::forward<T1>( lhs), std::forward<T2>( rhs) ;
229234 }
230235 }
231236
@@ -249,28 +254,101 @@ struct BinaryExpr {
249254 }
250255};
251256
252- template <std::size_t Idx>
257+ namespace _impl {
258+ template <auto V>
259+ struct value {};
260+
261+ template <typename T>
262+ constexpr inline auto non_special_members =
263+ define_static_array(members_of(^^T, std::meta::access_context::current()) |
264+ std::views::filter([](std::meta::info R) {
265+ return (is_function(R) or is_nonstatic_data_member(R)) and
266+ not is_special_member_function(R);
267+ }));
268+
269+ template <std::size_t Idx, typename T>
270+ decltype(auto) operator->*(T&& obj, value<Idx>) {
271+ static constexpr auto member = non_special_members<std::remove_cvref_t<T>>[Idx];
272+ // if constexpr (is_function(member)) {
273+ // // TODO check for getter annotation
274+ // if constexpr (is_static_member(member)) {
275+ // return [:member:];
276+ // } else {
277+ // return [&]<typename... Ts>(Ts&&... args) {
278+ // return std::forward<T>(obj).[:member:](std::forward<Ts>(args)...);
279+ // };
280+ // }
281+ // } else
282+ if constexpr (is_nonstatic_data_member(member)) {
283+ return std::forward<T>(obj).[:member:];
284+ } else if constexpr (requires {
285+ { get<Idx>(std::forward<T>(obj)) };
286+ }) {
287+ return get<Idx>(std::forward<T>(obj));
288+ } else {
289+ static_assert(false, std::string("Cannot get member") + util::utos(Idx));
290+ }
291+ }
292+ } // namespace _impl
293+
294+ template <std::size_t... Idx>
253295struct Placeholder {
254- constexpr decltype(auto) eval(auto const& args) const {
255- static constexpr auto placeholder_count =
256- std::tuple_size_v<std::remove_cvref_t<decltype(args)>>;
257- static_assert(Idx < placeholder_count,
258- std::string("Placeholder $") + util::utos(Idx) + " has no associated value");
259- return get<Idx>(args);
296+ template <typename T>
297+ constexpr decltype(auto) eval(T&& args) const {
298+ return (std::forward<T>(args)->*...->*_impl::value<Idx>{});
260299 }
261300
262- constexpr auto eval_verbose(auto const& args, std::vector<std::string>& failed_terms) const {
263- return eval(args);
301+ template <typename T>
302+ constexpr auto eval_verbose(T&& args, std::vector<std::string>& failed_terms) const {
303+ return eval(std::forward<T>(args));
264304 }
265305
266- constexpr std::string to_string(auto const& args) const {
306+ template <typename T>
307+ constexpr std::string to_string(T&& args) const {
267308 // TODO constexpr
268- return std::format("{}", get<Idx>(args));
309+ if constexpr (requires {
310+ { std::format("{}", eval(std::forward<T>(args))) };
311+ }) {
312+ return std::format("{}", eval(std::forward<T>(args)));
313+ }
314+ // TODO emit type name
315+ return "<obj>";
269316 }
270317
271318 constexpr std::string to_string(std::vector<std::string_view> const& replacements) const {
272- return std::string(replacements[Idx]);
319+ // TODO emit member names
320+ return std::string(replacements[Idx...[0]]);
321+ }
322+
323+ // TODO wrap call and subscript
324+ };
325+
326+ template <typename T, std::size_t... I>
327+ struct PlaceholderFor {
328+ struct Lazy;
329+
330+ consteval {
331+ std::vector<std::meta::info> members;
332+ auto idx = 0;
333+ for (auto member : _impl::non_special_members<std::remove_cvref_t<T>>) {
334+ std::meta::info type;
335+ if (is_class_type(remove_cvref(type_of(member)))) {
336+ type = substitute(^^PlaceholderFor,
337+ {remove_cvref(type_of(member)),
338+ std::meta::reflect_constant(I)...,
339+ std::meta::reflect_constant(idx++)});
340+ } else {
341+ // TODO does this need special handling for functions?
342+ type = substitute(^^Placeholder,
343+ {std::meta::reflect_constant(I)..., std::meta::reflect_constant(idx++)});
344+ }
345+
346+ members.push_back(data_member_spec(type, {.name = identifier_of(member)}));
347+ }
348+ define_aggregate(^^Lazy, members);
273349 }
350+
351+ Lazy* operator->() const { return nullptr; }
274352};
275353
276354template <typename T>
@@ -430,8 +508,54 @@ constexpr inline struct {
430508namespace rsl {
431509// using rsl::_expect_impl::expect;
432510using rsl::_expect_impl::Placeholder;
511+ template <typename T, std::size_t Idx>
512+ using TypedPlaceholder = _expect_impl::PlaceholderFor<T, Idx>;
513+
514+ namespace typed_placeholders {
515+ template <typename T>
516+ constexpr inline TypedPlaceholder<T, 0> _0{};
517+ template <typename T>
518+ constexpr inline TypedPlaceholder<T, 1> _1{};
519+ template <typename T>
520+ constexpr inline TypedPlaceholder<T, 2> _2{};
521+ template <typename T>
522+ constexpr inline TypedPlaceholder<T, 3> _3{};
523+ template <typename T>
524+ constexpr inline TypedPlaceholder<T, 4> _4{};
525+ template <typename T>
526+ constexpr inline TypedPlaceholder<T, 5> _5{};
527+ template <typename T>
528+ constexpr inline TypedPlaceholder<T, 6> _6{};
529+ template <typename T>
530+ constexpr inline TypedPlaceholder<T, 7> _7{};
531+ template <typename T>
532+ constexpr inline TypedPlaceholder<T, 8> _8{};
533+ template <typename T>
534+ constexpr inline TypedPlaceholder<T, 9> _9{};
535+ } // namespace typed_placeholders
433536
434537namespace placeholders {
538+ template <typename T>
539+ constexpr inline auto p0 = typed_placeholders::_0<T>;
540+ template <typename T>
541+ constexpr inline auto p1 = typed_placeholders::_1<T>;
542+ template <typename T>
543+ constexpr inline auto p2 = typed_placeholders::_2<T>;
544+ template <typename T>
545+ constexpr inline auto p3 = typed_placeholders::_3<T>;
546+ template <typename T>
547+ constexpr inline auto p4 = typed_placeholders::_4<T>;
548+ template <typename T>
549+ constexpr inline auto p5 = typed_placeholders::_5<T>;
550+ template <typename T>
551+ constexpr inline auto p6 = typed_placeholders::_6<T>;
552+ template <typename T>
553+ constexpr inline auto p7 = typed_placeholders::_7<T>;
554+ template <typename T>
555+ constexpr inline auto p8 = typed_placeholders::_8<T>;
556+ template <typename T>
557+ constexpr inline auto p9 = typed_placeholders::_9<T>;
558+
435559constexpr inline Placeholder<0> _0{};
436560constexpr inline Placeholder<1> _1{};
437561constexpr inline Placeholder<2> _2{};
@@ -442,6 +566,5 @@ constexpr inline Placeholder<6> _6{};
442566constexpr inline Placeholder<7> _7{};
443567constexpr inline Placeholder<8> _8{};
444568constexpr inline Placeholder<9> _9{};
445-
446569} // namespace placeholders
447570} // namespace rsl
0 commit comments