Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<pre><code> template&lt;unsigned LL = L&gt; Vector&lt;typename std::enable_if&lt;LL==3 &amp;&amp; L == 3, T&gt;::type, LL&gt; cross(const Vector&lt;T,LL&gt;&amp; vec2) const { Vector&lt;T,L&gt; result; result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1); result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2); result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0); return result; } </code></pre> <p>PS. Why this works this way?</p> <p>The definition of the variable <code>v4</code> causes an implicit instantiation of the class template <code>Vector</code>, which causes, in turn, implicit instantiation of the declarations of class member functions, among other things (14.7.1 Implicit instantiation [temp.inst] #1). This latter instantiation, of course, results in an error.</p> <p>If we instead change the member function to be a member template, according to the same clause, at this point <strong>the member template itself</strong> is instantiated and this instantiation looks, more or less, like:</p> <pre><code>template&lt;unsigned LL = 3&gt; Vector&lt;typename std::enable_if&lt;LL==3 &amp;&amp; 3 == 3, double&gt;::type, LL&gt; cross(const Vector&lt;double,LL&gt;&amp; vec2) const; </code></pre> <p>which is an entirely valid template declaration. We don't (and we cannot) perform any further instantiation at this point.</p> <p>However, when we attempt to actually call <code>cross</code>, this is without doubt, "a context that requires the member/function definition to exist", therefore, according to (14.7.1 Implicit instantiation [temp.inst] #2, #3), the <code>cross</code> template (the second <code>cross</code> template, the one that is a result of the outer class template instantiation) is implicitly instantiated and the <code>std::enable_if</code> is given opportunity to do its work. As a side note, this is the situation, where the SFINAE principle is applicable.</p> <p>PPS. To elaborate a bit further, although not directly connected with the OP question, but still worth mentioning that it's not always necessary to declare members as templates in order to handle similar situations.</p> <p>There are situations, where a member of a class template is not "valid" for a given instantiation, but still the class template can be instantiated, for example:</p> <pre><code>#include &lt;type_traits&gt; template&lt;typename T&gt; struct S { T x; T foo () const { return x; } typename std::remove_pointer&lt;T&gt;::type bar () const { return *x; } }; S&lt;int&gt; x; S&lt;int *&gt; y; </code></pre> <p>Apparently, in the instantiation <code>S&lt;int&gt;</code>, the expression <code>*x</code> is invalid, because the type of <code>x</code> is <code>int</code>. This program is correct, though. The important point is that during implicit instantiation only the <strong>declarations</strong> of the members are instantiated. In the above case, the instantiation <code>S&lt;int&gt;</code> causes the <strong>declaration</strong> <code>int bar() const;</code> to be instantiated, which is an entirely correct declaration.</p> <p>Of course, if we later attempt to instantiate the <strong>definition</strong> of <code>S&lt;int&gt;::bar</code>, like in:</p> <pre><code>void f() { x.foo (); // x.bar (); // error y.foo (); y.bar (); } </code></pre> <p>we will get an error.</p> <p>(This still follows from the above-mentioned two paragraphs of the C++standard)</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