@@ -30,65 +30,73 @@ namespace detail {
3030
3131template <typename T>
3232struct atomic_ref_base {
33- static_assert (sizeof (T) == sizeof (std::atomic<T>), " size mismatch" );
34- static_assert (
35- std::is_trivially_copyable_v<T>, " value not trivially-copyable" );
33+ using value_type = remove_cvref_t <T>;
34+
35+ private:
36+ using atomic_reference = copy_cvref_t <T, std::atomic<value_type>>&;
3637
37- using value_type = T;
38+ public:
39+ static_assert (
40+ sizeof (value_type) == sizeof (std::atomic<value_type>), " size mismatch" );
41+ static_assert (
42+ std::is_trivially_copyable_v<value_type>, " value not trivially-copyable" );
3843
3944 static inline constexpr std::size_t required_alignment =
40- alignof (std::atomic<T >);
45+ alignof (std::atomic<value_type >);
4146
4247 explicit atomic_ref_base (T& ref) : ref_(ref) { check_alignment_ (); }
4348 atomic_ref_base (atomic_ref_base const &) = default ;
4449
45- void store (T desired, std::memory_order order = std::memory_order_seq_cst)
46- const noexcept {
50+ void store (
51+ value_type desired,
52+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
4753 return atomic ().store (desired, order);
4854 }
4955
50- T load (std::memory_order order = std::memory_order_seq_cst) const noexcept {
56+ value_type load (
57+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
5158 return atomic ().load (order);
5259 }
5360
54- T exchange (T desired, std::memory_order order = std::memory_order_seq_cst)
55- const noexcept {
61+ value_type exchange (
62+ value_type desired,
63+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
5664 return atomic ().exchange (desired, order);
5765 }
5866
5967 bool compare_exchange_weak (
60- T & expected,
61- T desired,
68+ value_type & expected,
69+ value_type desired,
6270 std::memory_order success,
6371 std::memory_order failure) const noexcept {
6472 return atomic ().compare_exchange_weak (expected, desired, success, failure);
6573 }
6674
6775 bool compare_exchange_weak (
68- T & expected,
69- T desired,
76+ value_type & expected,
77+ value_type desired,
7078 std::memory_order order = std::memory_order_seq_cst) const noexcept {
7179 return atomic ().compare_exchange_weak (expected, desired, order);
7280 }
7381
7482 bool compare_exchange_strong (
75- T & expected,
76- T desired,
83+ value_type & expected,
84+ value_type desired,
7785 std::memory_order success,
7886 std::memory_order failure) const noexcept {
7987 return atomic ().compare_exchange_strong (
8088 expected, desired, success, failure);
8189 }
8290
8391 bool compare_exchange_strong (
84- T & expected,
85- T desired,
92+ value_type & expected,
93+ value_type desired,
8694 std::memory_order order = std::memory_order_seq_cst) const noexcept {
8795 return atomic ().compare_exchange_strong (expected, desired, order);
8896 }
8997
90- std::atomic<T>& atomic () const noexcept {
91- return reinterpret_cast <std::atomic<T>& >(ref_); // ub dragons be here
98+ atomic_reference atomic () const noexcept {
99+ return reinterpret_cast <atomic_reference >(ref_); // ub dragons be here
92100 }
93101
94102 private:
@@ -103,38 +111,45 @@ struct atomic_ref_base {
103111
104112template <typename T>
105113struct atomic_ref_integral_base : atomic_ref_base<T> {
114+ using typename atomic_ref_base<T>::value_type;
115+
106116 using atomic_ref_base<T>::atomic_ref_base;
107117 using atomic_ref_base<T>::atomic;
108118
109- T fetch_add (T arg, std::memory_order order = std::memory_order_seq_cst)
110- const noexcept {
119+ value_type fetch_add (
120+ value_type arg,
121+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
111122 return atomic ().fetch_add (arg, order);
112123 }
113124
114- T fetch_sub (T arg, std::memory_order order = std::memory_order_seq_cst)
115- const noexcept {
125+ value_type fetch_sub (
126+ value_type arg,
127+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
116128 return atomic ().fetch_sub (arg, order);
117129 }
118130
119- T fetch_and (T arg, std::memory_order order = std::memory_order_seq_cst)
120- const noexcept {
131+ value_type fetch_and (
132+ value_type arg,
133+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
121134 return atomic ().fetch_and (arg, order);
122135 }
123136
124- T fetch_or (T arg, std::memory_order order = std::memory_order_seq_cst)
125- const noexcept {
137+ value_type fetch_or (
138+ value_type arg,
139+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
126140 return atomic ().fetch_or (arg, order);
127141 }
128142
129- T fetch_xor (T arg, std::memory_order order = std::memory_order_seq_cst)
130- const noexcept {
143+ value_type fetch_xor (
144+ value_type arg,
145+ std::memory_order order = std::memory_order_seq_cst) const noexcept {
131146 return atomic ().fetch_xor (arg, order);
132147 }
133148};
134149
135- template <typename T>
150+ template <typename T, typename TD = remove_cvref_t <T> >
136151using atomic_ref_select = conditional_t <
137- std::is_integral<T >::value && !std::is_same<T , bool >::value,
152+ std::is_integral<TD >::value && !std::is_same<TD , bool >::value,
138153 atomic_ref_integral_base<T>,
139154 atomic_ref_base<T>>;
140155
@@ -166,10 +181,12 @@ atomic_ref(T&) -> atomic_ref<T>;
166181struct make_atomic_ref_t {
167182 template <
168183 typename T,
184+ typename ...,
185+ typename TD = remove_cvref_t <T>,
186+ typename ATD = std::atomic<TD>,
169187 std::enable_if_t <
170- std::is_trivially_copyable_v<T> &&
171- sizeof (T) == sizeof (std::atomic<T>) &&
172- alignof (T) == alignof (std::atomic<T>),
188+ std::is_trivially_copyable_v<TD> && //
189+ sizeof (TD) == sizeof (ATD) && alignof (TD) == alignof (ATD),
173190 int > = 0 >
174191 atomic_ref<T> operator ()(T& ref) const {
175192 return atomic_ref<T>{ref};
0 commit comments