@@ -1008,6 +1008,18 @@ class ConcurrentQueue
10081008 MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 ) return false ;
10091009 else return inner_enqueue<CanAlloc>(std::move (item));
10101010 }
1011+
1012+ // Enqueues a single item (by constructing it in-place from arguments).
1013+ // Allocates memory if required. Only fails if memory allocation fails (or implicit
1014+ // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
1015+ // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
1016+ // Thread-safe.
1017+ template <typename ... Args>
1018+ inline bool enqueue_emplace (Args&&... args)
1019+ {
1020+ MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 ) return false ;
1021+ else return inner_enqueue<CanAlloc>(std::forward<Args>(args)...);
1022+ }
10111023
10121024 // Enqueues a single item (by copying it) using an explicit producer token.
10131025 // Allocates memory if required. Only fails if memory allocation fails (or
@@ -1369,11 +1381,11 @@ class ConcurrentQueue
13691381 return static_cast <ExplicitProducer*>(token.producer )->ConcurrentQueue ::ExplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));
13701382 }
13711383
1372- template <AllocationMode canAlloc, typename U >
1373- inline bool inner_enqueue (U && element )
1384+ template <AllocationMode canAlloc, typename ... Args >
1385+ inline bool inner_enqueue (Args && ... args )
13741386 {
13751387 auto producer = get_or_add_implicit_producer ();
1376- return producer == nullptr ? false : producer->ConcurrentQueue ::ImplicitProducer::template enqueue<canAlloc>(std::forward<U>(element) );
1388+ return producer == nullptr ? false : producer->ConcurrentQueue ::ImplicitProducer::template enqueue<canAlloc>(std::forward<Args>(args)... );
13771389 }
13781390
13791391 template <AllocationMode canAlloc, typename It>
@@ -1845,8 +1857,8 @@ class ConcurrentQueue
18451857 }
18461858 }
18471859
1848- template <AllocationMode allocMode, typename U >
1849- inline bool enqueue (U&& element )
1860+ template <AllocationMode allocMode, typename ... Args >
1861+ inline bool enqueue (Args&&... args )
18501862 {
18511863 index_t currentTailIndex = this ->tailIndex .load (std::memory_order_relaxed);
18521864 index_t newTailIndex = 1 + currentTailIndex;
@@ -1912,11 +1924,11 @@ class ConcurrentQueue
19121924 ++pr_blockIndexSlotsUsed;
19131925 }
19141926
1915- MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<U>(element) ))) {
1927+ MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<Args>(args)... ))) {
19161928 // The constructor may throw. We want the element not to appear in the queue in
19171929 // that case (without corrupting the queue):
19181930 MOODYCAMEL_TRY {
1919- new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<U>(element) );
1931+ new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<Args>(args)... );
19201932 }
19211933 MOODYCAMEL_CATCH (...) {
19221934 // Revert change to the current block, but leave the new block available
@@ -1938,14 +1950,14 @@ class ConcurrentQueue
19381950 blockIndex.load (std::memory_order_relaxed)->front .store (pr_blockIndexFront, std::memory_order_release);
19391951 pr_blockIndexFront = (pr_blockIndexFront + 1 ) & (pr_blockIndexSize - 1 );
19401952
1941- MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<U>(element) ))) {
1953+ MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<Args>(args)... ))) {
19421954 this ->tailIndex .store (newTailIndex, std::memory_order_release);
19431955 return true ;
19441956 }
19451957 }
19461958
19471959 // Enqueue
1948- new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<U>(element) );
1960+ new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<Args>(args)... );
19491961
19501962 this ->tailIndex .store (newTailIndex, std::memory_order_release);
19511963 return true ;
@@ -2483,8 +2495,8 @@ class ConcurrentQueue
24832495 }
24842496 }
24852497
2486- template <AllocationMode allocMode, typename U >
2487- inline bool enqueue (U&& element )
2498+ template <AllocationMode allocMode, typename ... Args >
2499+ inline bool enqueue (Args&&... args )
24882500 {
24892501 index_t currentTailIndex = this ->tailIndex .load (std::memory_order_relaxed);
24902502 index_t newTailIndex = 1 + currentTailIndex;
@@ -2516,10 +2528,10 @@ class ConcurrentQueue
25162528#endif
25172529 newBlock->ConcurrentQueue ::Block::template reset_empty<implicit_context>();
25182530
2519- MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<U>(element) ))) {
2531+ MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<Args>(args)... ))) {
25202532 // May throw, try to insert now before we publish the fact that we have this new block
25212533 MOODYCAMEL_TRY {
2522- new ((*newBlock)[currentTailIndex]) T (std::forward<U>(element) );
2534+ new ((*newBlock)[currentTailIndex]) T (std::forward<Args>(args)... );
25232535 }
25242536 MOODYCAMEL_CATCH (...) {
25252537 rewind_block_index_tail ();
@@ -2534,14 +2546,14 @@ class ConcurrentQueue
25342546
25352547 this ->tailBlock = newBlock;
25362548
2537- MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<U>(element) ))) {
2549+ MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR (T, U, new (static_cast <T*>(nullptr )) T (std::forward<Args>(args)... ))) {
25382550 this ->tailIndex .store (newTailIndex, std::memory_order_release);
25392551 return true ;
25402552 }
25412553 }
25422554
25432555 // Enqueue
2544- new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<U>(element) );
2556+ new ((*this ->tailBlock )[currentTailIndex]) T (std::forward<Args>(args)... );
25452557
25462558 this ->tailIndex .store (newTailIndex, std::memory_order_release);
25472559 return true ;
0 commit comments