Note that there are some explanatory texts on larger screens.

plurals
  1. POStrange behavior of operators with CRTP and template specialization
    primarykey
    data
    text
    <p>I'm writing a vector template with a few specializations so that there are named accessors for the first few items of the vector (such x, y, z, w) depending on the size. <a href="https://stackoverflow.com/a/8645315/140367">KennyTM's answer</a> was a great help with this. I also added a form of <a href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern" rel="nofollow noreferrer">Curiously recurring template pattern</a> to be able to use the operators naturally. Here is the base class and a specialization with added functions (omitted most member implementations for brevity): </p> <pre><code>template&lt;int Dim, typename V, typename ItemType = float&gt; class VectorImpl { public: typedef ItemType value_type; VectorImpl() { elements.fill(0); } VectorImpl(std::initializer_list&lt;ItemType&gt; init_list); V operator+(const V&amp; other) { V result; for (int i = 0; i &lt; Dim; ++i) result.elements[i] = elements[i] + other.elements[i]; return result; } QString toString(); // ... other members ... protected: VectorImpl(const VectorImpl&amp; other) = default; protected: std::array&lt;ItemType, Dim&gt; elements; }; template&lt;int Dim, typename ItemType = float&gt; class Vector : public VectorImpl&lt;Dim, Vector&lt;Dim, ItemType&gt;, ItemType&gt; { typedef VectorImpl&lt;Dim, Vector&lt;Dim, ItemType&gt;, ItemType&gt; ParentType; public: Vector() : ParentType() {} Vector(const ParentType&amp; other) : ParentType(other) {} Vector(std::initializer_list&lt;ItemType&gt; init_list) : ParentType(init_list) {} }; template&lt;typename ItemType&gt; class Vector&lt;3, ItemType&gt; : public VectorImpl&lt;3, Vector&lt;3, ItemType&gt;, ItemType&gt; { typedef VectorImpl&lt;3, Vector&lt;3, ItemType&gt;, ItemType&gt; ParentType; public: Vector() : ParentType() {} Vector(const ParentType&amp; other) : ParentType(other) {} Vector(std::initializer_list&lt;ItemType&gt; init_list) : ParentType(init_list) {} ItemType x() const { return this-&gt;elements[0]; } ItemType y() const { return this-&gt;elements[1]; } ItemType z() const { return this-&gt;elements[2]; } }; </code></pre> <p>And I wanted to add <code>qDebug()&lt;&lt;</code> support, so I did this:</p> <pre><code>template&lt;int Dim, typename ItemType&gt; QDebug operator&lt;&lt;(QDebug dbg, Vector&lt;Dim, ItemType&gt;&amp; v) { dbg.nospace() &lt;&lt; v.toString(); return dbg.space(); } </code></pre> <p>Now, the following code compiles and works:</p> <pre><code>Vector&lt;3&gt; v1 = { 3,4,5 }; qDebug() &lt;&lt; v1; </code></pre> <p>This one does, too:</p> <pre><code>Vector&lt;3&gt; v1 = { 3,4,5 }; Vector&lt;3&gt; v2 = { 1,-1,1 }; qDebug() &lt;&lt; v1; auto v3 = v1 + v2; qDebug() &lt;&lt; v3; </code></pre> <p>But this one does not:</p> <pre><code>Vector&lt;3&gt; v1 = { 3,4,5 }; Vector&lt;3&gt; v2 = { 1,-1,1 }; qDebug() &lt;&lt; (v1 + v2); </code></pre> <p>The compiler says: </p> <blockquote> <p>error: no match for 'operator&lt;&lt;' in 'qDebug()() &lt;&lt; v1.Vector&lt;3>::.VectorImpl::operator+ [with int Dim = 3, V = Vector&lt;3>, ItemType = float]((*(const Vector&lt;3>*)(&amp; v2)))'</p> </blockquote> <p>What is going on? Why is the type of <code>v1 + v2</code> different when assigning to a variable? What should I do to make this compile?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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