Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This is a classic example of the need to perfectly forward. Do this by templating the function (member template if this is a member function):</p> <pre><code>template &lt;class U&gt; void enqueue(U&amp;&amp; item) { std::unique_lock&lt;std::mutex&gt; lock(m); this-&gt;push(std::forward&lt;U&gt;(item)); this-&gt;data_available = true; cv.notify_one(); } </code></pre> <p>Explanation: If you pass an lvalue <code>T</code> to <code>enqueue</code>, <code>U</code> will deduce to <code>T&amp;</code>, and the <code>forward</code> will pass it along as an lvalue, and you'll get the copy behavior you want. If you pass an rvalue <code>T</code> to <code>enqueue</code>, <code>U</code> will deduce to <code>T</code>, and the <code>forward</code> will pass it along as an rvalue, and you'll get the move behavior you want.</p> <p>This is more efficient than the "pass by value" approach in that you never make an unnecessary copy or move. The downside with respect to the "pass by value" approach is that the function accepts anything, even if it is wrong. You may or may not get cascaded errors down under the <code>push</code>. If this is a concern, you can <code>enable_if enqueue</code> to restrict what arguments it will instantiate with.</p> <p><strong>Update based on comment</strong></p> <p>Based on the comments below, this is what I understand things look like:</p> <pre><code>#include &lt;queue&gt; #include &lt;mutex&gt; #include &lt;condition_variable&gt; template &lt;class T&gt; class Mine : public std::queue&lt;T&gt; { std::mutex m; std::condition_variable cv; bool data_available = false; public: template &lt;class U&gt; void enqueue(U&amp;&amp; item) { std::unique_lock&lt;std::mutex&gt; lock(m); this-&gt;push(std::forward&lt;U&gt;(item)); this-&gt;data_available = true; cv.notify_one(); } }; int main() { Mine&lt;int&gt; q; q.enqueue(1); } </code></pre> <p>This is all good. But what if you try to enqueue a double instead:</p> <pre><code>q.enqueue(1.0); </code></pre> <p>This still works because the double is implicitly convertible to the int. But what if you didn't want it to work? Then you could restrict your <code>enqueue</code> like this:</p> <pre><code>template &lt;class U&gt; typename std::enable_if &lt; std::is_same&lt;typename std::decay&lt;U&gt;::type, T&gt;::value &gt;::type enqueue(U&amp;&amp; item) { std::unique_lock&lt;std::mutex&gt; lock(m); this-&gt;push(std::forward&lt;U&gt;(item)); this-&gt;data_available = true; cv.notify_one(); } </code></pre> <p>Now:</p> <pre><code>q.enqueue(1.0); </code></pre> <p>results in:</p> <pre><code>test.cpp:31:11: error: no matching member function for call to 'enqueue' q.enqueue(1.0); ~~^~~~~~~ test.cpp:16:13: note: candidate template ignored: disabled by 'enable_if' [with U = double] std::is_same&lt;typename std::decay&lt;U&gt;::type, T&gt;::value ^ 1 error generated. </code></pre> <p>But <code>q.enqueue(1);</code> will still work fine. I.e. restricting your member template is a design decision you need to make. What <code>U</code> do you want <code>enqueue</code> to accept? There is no right or wrong answer. This is an engineering judgment. And several other tests are available that may be more appropriate (e.g. std::is_convertible, std::is_constructible, etc.). Maybe the right answer for your application is no constraint at all, as first prototyped above.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload