Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I believe Kerrek SB's answer is partially right, but incomplete. It fails in that <code>C&lt;T&gt;</code>'s constructor is overly generic. That is, <code>C&lt;T&gt;</code> will construct from anything if you just look at its constructor declaration. You don't find out otherwise until you've selected the constructor and you're instantiating. And by then it is too late.</p> <p>Concrete example:</p> <p>Let's say that <code>C&lt;T&gt;</code> has:</p> <pre><code>friend bool operator&lt;(const C&amp;, const C&amp;); </code></pre> <p>And now you want to make <code>C&lt;T&gt;</code> the key in a <code>map</code>:</p> <pre><code>std::map&lt;C&lt;A&gt;, int&gt; m; // ... m.erase(m.begin()); </code></pre> <p>This is an error because there are two <code>erase</code> overloads which now look like:</p> <pre><code>iterator erase(const_iterator position); size_type erase(const key_type&amp; k); </code></pre> <p>and <code>m.begin()</code> is an <code>iterator</code>. This <code>iterator</code> will convert with equal ease to both <code>const_iterator</code> and <code>key_type</code> (aka <code>C&lt;A&gt;</code>).</p> <p>Now this can be fixed by calling:</p> <pre><code>m.erase(m.cbegin()); </code></pre> <p>instead. But this is just the tip of the iceberg on problems that overly generic constructors cause. For example any code that branches on:</p> <pre><code>std::is_constructible&lt;C&lt;A&gt;, any type and any number of them&gt;::value </code></pre> <p>is likely to get false positives because the above will <strong>always</strong> return true.</p> <p>The fix is a little messy, but very practical:</p> <pre><code>template&lt;typename T&gt; struct C { template &lt;class ...Args, class = typename std::enable_if &lt; std::is_constructible&lt;T, Args...&gt;::value &gt;::type &gt; C(Args&amp;&amp; ...args) : _t(new T(std::forward&lt;Args&gt;(args)...)) { } // ... }; </code></pre> <p>I.e. Add a constraint to the constructor such that it won't be instantiated if it isn't going to work. This is messy, ugly, whatever. Perhaps you want to dress it up with a macro. Fine. But it makes this class <strong>work</strong> where <em>otherwise</em> it is <strong>broken</strong> in the examples I mention above (and numerous other problems that tend to trickle in as bug reports one at a time over a period of years).</p> <p>In addition to Kerrek SB's good advice on using <code>unique_ptr&lt;T&gt;</code> over a raw pointer here, I would like to add:</p> <ol> <li><p>That this constructor should probably be <code>explicit</code>, at least until it is shown by actual use cases that it really needs to be implicit.</p></li> <li><p>Consider storing a <code>T</code> instead of a (possibly smart) pointer to <code>T</code>. You don't need pointer semantics unless you're actually trying to point to a base class to achieve run-time polymorphism.</p></li> </ol> <p>In summary: be wary of overly generic code, and downright paranoid of overly generic constructors.</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