112
112
*
113
113
* The container type must support the following (depending on which
114
114
* methods are called): default construction, construction with an initial size,
115
- * @c push_back (preferably overloaded for both copy and move),
115
+ * @c push_back (preferably overloaded for both copy and move semantics ),
116
116
* @c emplace_back (with a template parameter pack), @c front, @c pop_front,
117
117
* @c empty, and @c size. The container must also have a @c size_type
118
- * defined.
118
+ * defined. Type constraints and concepts are defined for the various
119
+ * type requirements.
119
120
*
120
121
* Iterators on a @c wait_queue are not supported, due to obvious difficulties
121
122
* with maintaining consistency and integrity. The @c apply method can be used to
159
160
#include < optional>
160
161
#include < utility> // std::move, std::move_if_noexcept
161
162
#include < type_traits> // for requires clauses and noexcept specs
163
+ #include < concepts>
162
164
163
165
namespace chops {
164
166
167
+ // requirements for wait_queue container
168
+
169
+ template <typename Ctr, typename T>
170
+ concept supports_push_back = requires (Ctr ctr, T val) {
171
+ ctr.push_back (val);
172
+ };
173
+
174
+ template <typename Ctr, typename ... Args>
175
+ concept supports_emplace_back = requires (Ctr ctr, Args args) {
176
+ ctr.emplace_back (args);
177
+ };
178
+
179
+ template <typename Ctr>
180
+ concept supports_empty = requires (Ctr ctr) {
181
+ ctr.empty ();
182
+ };
183
+
184
+ template <typename Ctr>
185
+ concept supports_pop_front = requires (Ctr ctr) {
186
+ ctr.pop_front ();
187
+ };
188
+
189
+ template <typename Ctr>
190
+ concept supports_size = requires (Ctr ctr) {
191
+ ctr.size ();
192
+ };
193
+
194
+ // declaration for wait_queue
195
+
165
196
template <typename T, typename Container = std::deque<T> >
166
197
requires std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>
167
198
class wait_queue {
@@ -375,7 +406,7 @@ class wait_queue {
375
406
*/
376
407
auto push (const T& val) /* noexcept(std::is_nothrow_copy_constructible_v<T>) */
377
408
-> bool
378
- requires requires (T val, Container c) { c. push_back (val); }
409
+ requires supports_push_back<Container, T>
379
410
380
411
{
381
412
if (m_stop_tok.stop_requested ()) {
@@ -399,7 +430,7 @@ class wait_queue {
399
430
*/
400
431
auto push (T&& val) /* noexcept(std::is_nothrow_move_constructible_v<T>) */
401
432
-> bool
402
- requires requires (T val, Container c) { c. push_back (val); }
433
+ requires supports_push_back<Container, T>
403
434
404
435
{
405
436
if (m_stop_tok.stop_requested ()) {
@@ -431,7 +462,7 @@ class wait_queue {
431
462
template <typename ... Args>
432
463
auto emplace_push (Args &&... args) /* noexcept(std::is_nothrow_constructible_v<T, Args...>)*/
433
464
-> bool
434
- // requires requires ( Container c) { c.emplace_back(); }
465
+ requires supports_emplace_back< Container, Args...>
435
466
436
467
{
437
468
if (m_stop_tok.stop_requested ()) {
@@ -459,7 +490,7 @@ class wait_queue {
459
490
*/
460
491
[[nodiscard]] auto wait_and_pop () /* noexcept(std::is_nothrow_constructible_v<T>) */
461
492
-> std::optional<T>
462
- requires requires ( Container c) { c. empty (); c. pop_front (); }
493
+ requires supports_empty< Container> && supports_pop_front<Container>
463
494
464
495
{
465
496
std::unique_lock<std::mutex> lk{m_mut};
@@ -490,7 +521,7 @@ class wait_queue {
490
521
*/
491
522
[[nodiscard]] auto try_pop () /* noexcept(std::is_nothrow_constructible_v<T>) */
492
523
-> std::optional<T>
493
- requires requires ( Container c) { c. empty (); c. pop_front (); }
524
+ requires supports_empty< Container> && supports_pop_front<Container>
494
525
{
495
526
if (m_stop_tok.stop_requested ()) {
496
527
return std::optional<T> {};
@@ -539,7 +570,7 @@ class wait_queue {
539
570
template <typename F>
540
571
auto apply (F&& func) const /* noexcept(std::is_nothrow_invocable_v<F&&, const T&>) */
541
572
-> void
542
- requires requires (T elem, F func) { func (elem); }
573
+ requires std::is_invocable_v<F, T>
543
574
544
575
{
545
576
lock_guard lk{m_mut};
@@ -569,7 +600,7 @@ class wait_queue {
569
600
*/
570
601
[[nodiscard]] auto empty () const /* noexcept */
571
602
-> bool
572
- requires requires ( Container c) { c. empty (); }
603
+ requires supports_empty< Container>
573
604
574
605
{
575
606
lock_guard lk{m_mut};
@@ -584,7 +615,7 @@ class wait_queue {
584
615
*/
585
616
[[nodiscard]] auto size () const /* noexcept */
586
617
-> size_type
587
- requires requires ( Container c) { c. size (); }
618
+ requires supports_size< Container>
588
619
589
620
{
590
621
lock_guard lk{m_mut};
0 commit comments