15 #include <shared_mutex>
17 #include <type_traits>
25 template <
typename Value,
typename Mutex = std::mutex,
26 typename ReadLock = std::conditional_t<std::is_same_v<std::shared_mutex, Mutex>, std::shared_lock<Mutex>,
27 std::lock_guard<Mutex>>,
28 typename WriteLock = std::lock_guard<Mutex>>
30 static_assert( !std::is_reference_v<Value>,
"Value must not be a reference" );
35 template <
typename... Args>
36 requires( std::is_constructible_v<Value, Args...> )
40 static_assert( std::is_default_constructible_v<Value> );
43 static_assert( std::is_copy_assignable_v<Value> );
44 auto lock = std::scoped_lock{ rhs.
m_mtx,
m_mtx };
49 static_assert( std::is_copy_assignable_v<Value> );
51 auto lock = std::scoped_lock{ rhs.
m_mtx,
m_mtx };
58 static_assert( std::is_default_constructible_v<Value> );
61 static_assert( std::is_move_assignable_v<Value> );
62 auto lock = std::scoped_lock{ rhs.m_mtx,
m_mtx };
63 m_obj = std::move( rhs.m_obj );
67 static_assert( std::is_move_assignable_v<Value> );
69 auto lock = std::scoped_lock{ rhs.m_mtx,
m_mtx };
70 m_obj = std::move( rhs.m_obj );
75 template <
typename... Args, std::invocable<
Value&, Args...> F>
76 requires( !std::is_invocable_v<F, const Value&, Args...> )
79 return std::invoke( std::forward<F>( f ),
m_obj, std::forward<Args>(
args )... );
82 template <
typename... Args, std::invocable<
const Value&, Args...> F>
85 return std::invoke( std::forward<F>( f ),
m_obj, std::forward<Args>(
args )... );
90 template <
typename Fun>
92 return [f = std::forward<Fun>( f )](
auto& p,
auto&&...
args ) -> decltype(
auto ) {
93 return p.with_lock( f, std::forward<decltype(
args )>(
args )... );
97 template <
typename ContainerOfSynced,
typename Fun>