@@ -90,7 +90,10 @@ namespace Nui
9090 using BasicObservedRange<ObservedRange<ObservedValue>>::before_;
9191 using BasicObservedRange<ObservedRange<ObservedValue>>::after_;
9292
93- static constexpr bool isRandomAccess = ObservedType::isRandomAccess;
93+ // Unwrap through shared_ptr/weak_ptr<Observed> so the trait reads from the
94+ // underlying Observed rather than the smart pointer (which has no isRandomAccess).
95+ static constexpr bool isRandomAccess =
96+ Detail::ObservedAddMutableReference_raw<ObservedType>::isRandomAccess;
9497
9598 template <typename ObservedValueT>
9699 requires std::is_same_v<std::decay_t <ObservedValueT>, std::decay_t <ObservedValueT>>
@@ -166,7 +169,24 @@ namespace Nui
166169 return ObservedRange<const ObservedValue>{observedValues};
167170 }
168171
172+ /* *
173+ * @brief Reactive range over a shared_ptr/weak_ptr<Observed<Container>>.
174+ *
175+ * The smart pointer is stored internally as a weak_ptr (matching how shared/weak
176+ * observed are treated elsewhere), locked per update, so the range reacts to
177+ * mutations and reassignment of the underlying Observed. The caller must keep the
178+ * shared_ptr alive for as long as the rendered range is mounted. Taken by value so
179+ * the weak_ptr conversion is well-formed for both shared_ptr and weak_ptr inputs.
180+ */
181+ template <typename ObservedValue>
182+ requires (IsSharedObserved<ObservedValue> || IsWeakObserved<ObservedValue>)
183+ ObservedRange<std::decay_t <ObservedValue>> range (ObservedValue observedValues)
184+ {
185+ return ObservedRange<std::decay_t <ObservedValue>>{std::move (observedValues)};
186+ }
187+
169188 template <typename ContainerT, typename ... Observed>
189+ requires (!IsObservedLike<std::remove_cvref_t <ContainerT>>)
170190 UnoptimizedRange<IteratorAccessor<ContainerT const >, std::decay_t <Detail::ObservedAddReference_t<Observed>>...>
171191 range (ContainerT const & container, Observed&&... observed)
172192 {
@@ -179,6 +199,7 @@ namespace Nui
179199 }
180200
181201 template <typename ContainerT, typename ... Observed>
202+ requires (!IsObservedLike<std::remove_cvref_t <ContainerT>>)
182203 UnoptimizedRange<IteratorAccessor<ContainerT>, std::decay_t <Detail::ObservedAddReference_t<Observed>>...>
183204 range (ContainerT& container, Observed&&... observed)
184205 {
@@ -237,6 +258,7 @@ namespace Nui
237258 }
238259
239260 template <typename ContainerT>
261+ requires (!IsObservedLike<std::remove_cvref_t <ContainerT>>)
240262 UnoptimizedRange<IteratorAccessor<ContainerT const >> range (ContainerT const & container)
241263 {
242264 return UnoptimizedRange<IteratorAccessor<ContainerT const >>{
@@ -250,7 +272,7 @@ namespace Nui
250272 * even if the caller's local container goes out of scope immediately.
251273 */
252274 template <typename ContainerT>
253- requires (!IsObserved <std::remove_cvref_t <ContainerT>>)
275+ requires (!IsObservedLike <std::remove_cvref_t <ContainerT>>)
254276 UnoptimizedRange<OwningIteratorAccessor<std::remove_cvref_t <ContainerT>>>
255277 range (ContainerT&& container)
256278 {
@@ -262,6 +284,7 @@ namespace Nui
262284
263285#ifdef NUI_HAS_STD_RANGES
264286 template <typename T, typename ... Observed>
287+ requires (!IsObservedLike<std::remove_cvref_t <T>>)
265288 UnoptimizedRange<
266289 std::ranges::subrange<std::ranges::iterator_t<T const >>,
267290 std::decay_t<Detail::ObservedAddReference_t<Observed>>...> range(T const & container, Observed&&... observed)
0 commit comments