|
6 | 6 | #include "injector.hpp" |
7 | 7 | #include "tag.hpp" |
8 | 8 | #include "source.hpp" |
| 9 | +#include "source_types.hpp" |
9 | 10 | #include "source_reference_wrapper.hpp" |
10 | 11 | #include "source_helper.hpp" |
11 | 12 |
|
@@ -230,13 +231,16 @@ namespace kangaru { |
230 | 231 | if constexpr (reference_wrapper<Source>) { |
231 | 232 | return std::as_const(source.construction).template operator()<T>(KANGARU5_FWD(source).source); |
232 | 233 | } else { |
233 | | - return std::as_const(source.construction).template operator()<T>(kangaru::fwd_ref(KANGARU5_FWD(source).source)); |
| 234 | + return std::as_const(source.construction).template operator()<T>(KANGARU5_NO_ADL(fwd_ref)(KANGARU5_FWD(source).source)); |
234 | 235 | } |
235 | 236 | } |
236 | 237 |
|
237 | | - template<forwarded<with_construction> Original, forwarded_source NewSource> |
238 | | - static constexpr auto rebind(Original&& original, NewSource&& new_source) -> with_construction<std::decay_t<NewSource>, Construction> { |
239 | | - return with_construction<std::decay_t<NewSource>, Construction>{KANGARU5_FWD(new_source), original.construction}; |
| 238 | + template<forwarded<with_construction> Original, forwarded_source NewLeaf> |
| 239 | + static constexpr auto rebind(Original&& original, NewLeaf&& new_leaf) noexcept -> with_construction<rebind_wrapped_source_result_t<Original, NewLeaf>, Construction> { |
| 240 | + return with_construction<rebind_wrapped_source_result_t<Original, NewLeaf>, Construction>{ |
| 241 | + kangaru::rebind(KANGARU5_FWD(original).source, KANGARU5_FWD(new_leaf)), |
| 242 | + original.construction |
| 243 | + }; |
240 | 244 | } |
241 | 245 |
|
242 | 246 | Source source; |
@@ -284,37 +288,53 @@ namespace kangaru { |
284 | 288 | // By wrapping source_of in a type, we allow that type to be incomplete! |
285 | 289 | template<kangaru::source Source, kangaru::injectable T> |
286 | 290 | struct source_of_sfinae_wrapper : std::bool_constant<source_of<Source, T>> {}; |
| 291 | + |
| 292 | + template<kangaru::source Alternative> |
| 293 | + struct leaf_as_alternative { |
| 294 | + Alternative alternative; |
| 295 | + |
| 296 | + constexpr auto operator()(forwarded_source auto&& leaf) const noexcept { |
| 297 | + return KANGARU5_NO_ADL(make_source_with_alternative)( |
| 298 | + KANGARU5_NO_ADL(fwd_ref)(KANGARU5_FWD(leaf)), |
| 299 | + alternative |
| 300 | + ); |
| 301 | + } |
| 302 | + }; |
287 | 303 | } |
288 | 304 |
|
289 | | - template<source Source> |
| 305 | + template<rebindable_source Source> |
290 | 306 | struct with_recursion { |
291 | | - private: |
292 | | - static constexpr auto rebound_self(auto&& self) requires wrapping_source<std::remove_reference_t<decltype(self)>> { |
293 | | - auto const source_ref = KANGARU5_NO_ADL(ref)(KANGARU5_NO_ADL(maybe_unwrap)(self.source)); |
294 | | - return with_recursion<decltype(source_ref)>{source_ref}; |
295 | | - } |
296 | | - |
297 | | - template<forwarded<with_recursion> Self> |
298 | | - using rebound_source_t = decltype( |
299 | | - detail::source_helper::rebind_source_tree( |
300 | | - rebound_self(std::declval<Self&>()), |
301 | | - std::declval<Self&>().source |
302 | | - ) |
303 | | - ); |
304 | | - |
305 | | - public: |
306 | | - explicit constexpr with_recursion(Source source) noexcept : source{std::move(source)} {} |
307 | | - |
308 | 307 | Source source; |
309 | 308 |
|
310 | 309 | template<typename T, forwarded<with_recursion> Self> requires (not wrapping_source_of<Self, T>) |
311 | 310 | constexpr KANGARU5_PROVIDE_FUNCTION_DECL(Self&& source) -> T requires( |
312 | | - detail::recursive_source::source_of_sfinae_wrapper<rebound_source_t<Self>, T>::value |
| 311 | + // We uses the sfinae wrapper for source_of |
| 312 | + // This forces the compiler to have a third state: |
| 313 | + // requires(true) --> goes in |
| 314 | + // requires(false) --> tries another function |
| 315 | + // requires(<substitution-error>) --> tries another function |
| 316 | + // |
| 317 | + // The first time the compiler encounter provide, it check source_of |
| 318 | + // Then during the evaluation of source_of, it will encounter provide again |
| 319 | + // But instead of evaluating source_of, it will see source_of as an incomplete type |
| 320 | + // Thus skipping that function and try the next one and detect that one is callable |
| 321 | + // The evaluation of source_of will then yeild true, but |
| 322 | + // also yield false if it would result in infinite recursion |
| 323 | + // Yes, this requires expression will yield different result depending on the metastate of the compiler! |
| 324 | + detail::recursive_source::source_of_sfinae_wrapper< |
| 325 | + rebind_wrapped_source_result_t< |
| 326 | + Self&, |
| 327 | + detail::recursive_source::leaf_as_alternative<with_recursion<source_ref_t<wrapped_source_t<Self>>>> |
| 328 | + >, |
| 329 | + T |
| 330 | + >::value |
313 | 331 | ) { |
314 | 332 | return kangaru::provide<T>( |
315 | | - detail::source_helper::rebind_source_tree( |
316 | | - rebound_self(source), |
317 | | - source.source |
| 333 | + kangaru::rebind( |
| 334 | + source, |
| 335 | + detail::recursive_source::leaf_as_alternative<with_recursion<source_ref_t<wrapped_source_t<Self>>>>{ |
| 336 | + KANGARU5_NO_ADL(ref)(source.source) |
| 337 | + } |
318 | 338 | ) |
319 | 339 | ); |
320 | 340 | } |
|
0 commit comments