Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:</p> <pre><code>template&lt;typename T, typename U&gt; void f() {} //okay - primary template template&lt;typename T&gt; void f&lt;T,int&gt;() {} //error - partial specialization template&lt;&gt; void f&lt;unsigned char,int&gt;() {} //okay - full specialization </code></pre> <p>But you can partially specialize the class template itself. You can do something like this:</p> <pre><code>template &lt;class A&gt; class Thing&lt;A,int&gt; //partial specialization of the class template { //.. int doSomething(); }; template &lt;class A&gt; int Thing&lt;A,int&gt;::doSomething() { /* do whatever you want to do here */ } </code></pre> <p>Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), <strong>must match</strong> the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:</p> <pre><code>template &lt;class A&gt; int Thing&lt;A,double&gt;::doSomething(); //error </code></pre> <p>Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,</p> <blockquote> <p>The template parameter list of a member of a class template partial specialization <strong>shall match</strong> the template parameter list of the class template partial specialization.[...]</p> </blockquote> <p>For more on this, read my answer here:</p> <p><a href="https://stackoverflow.com/questions/5206080/c-overload-templated-class-method-with-a-partial-specilization-of-that-method/5206117#5206117">C++ - Overload templated class method with a partial specilization of that method</a></p> <hr> <p>So what is the solution? Would you partially specialize your class along with all the repetitive work?</p> <p>A simple solution would be work delegation, instead of partially specializing the class template. Write a <em>stand-alone</em> function template and specialize this as:</p> <pre><code>template &lt;class B&gt; B doTheActualSomething(B &amp; b) { return b; } template &lt;&gt; int doTheActualSomething&lt;int&gt;(int &amp; b) { return b + 1; } </code></pre> <p>And then call this function template from <code>doSomething()</code> member function as:</p> <pre><code>template &lt;class A, class B&gt; B Thing&lt;A,B&gt;::doSomething() { return doTheActualSomething&lt;B&gt;(b_); } </code></pre> <hr> <p>Since in your particular case, <code>doTheActualSomething</code> needs to know the value of <em>only one</em> member, namely <code>b_</code>, the above solution is fine, as you can pass the value to the function as argument whose type is the template <em>type</em> argument <code>B</code>, and specialization for <code>int</code> is possible being it full-specialization.</p> <p>But imagine if it needs to access multiple members, <em>type</em> of each depends on the template <em>type</em> argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one <em>type</em> argument to the function template, and you cannot <em>partially</em> specialize the function for just, say, one <em>type</em> (as its not allowed).</p> <p>So in this case you can define a class template instead, which defines a static non-template member function <code>doTheActualSomething</code>. Here is how:</p> <pre><code>template&lt;typename A, typename B&gt; struct Worker { B doTheActualSomething(Thing&lt;A,B&gt; *thing) { return thing-&gt;b_; } }; //partial specialization of the class template itself, for B = int template&lt;typename A&gt; struct Worker&lt;A,int&gt; { int doTheActualSomething(Thing&lt;A,int&gt; *thing) { return thing-&gt;b_ + 1; } }; </code></pre> <p>Notice that you can use <code>thing</code> pointer to access any member of the class. Of course, if it needs to access private members, then you've to make <code>struct Worker</code> a friend of <code>Thing</code> class template, as:</p> <pre><code>//forward class template declaration template&lt;typename T, typename U&gt; struct Worker template &lt;class A, class B&gt; class Thing { template&lt;typename T, typename U&gt; friend struct Worker; //make it friend //... }; </code></pre> <p>Now delegate the work to the friend as:</p> <pre><code>template &lt;class A, class B&gt; B Thing&lt;A,B&gt;::doSomething() { return Worker&lt;A,B&gt;::doTheActualSomething(this); //delegate work } </code></pre> <p>Two points to be noted here:</p> <ul> <li>In this solution, <code>doTheActualSomething</code> is not a member function <em>template</em>. Its not enclosing class which is template. Hence we can <em>partially</em> specialize the class template anytime, to get the desired effect of the <em>partial</em> member function template specialization.</li> <li>Since we pass <code>this</code> pointer as argument to the function, we can access any member of the class <code>Thing&lt;A,B&gt;</code>, even private members, as <code>Worker&lt;T,U&gt;</code> is also a friend.</li> </ul> <p>Complete online demo : <a href="http://www.ideone.com/uEQ4S" rel="noreferrer">http://www.ideone.com/uEQ4S</a></p> <hr> <p>Now there is still a chance of improvement. Now all instantiations of <code>Worker</code> class template are friends of all instantiation of <code>Thing</code> class template. So we can restrict this many-to-many friendship as:</p> <pre><code>template &lt;class A, class B&gt; class Thing { friend struct Worker&lt;A,B&gt;; //make it friend //... }; </code></pre> <p>Now only one instantiation of <code>Worker</code> class template is a friend of one instantiation of <code>Thing</code> class template. That is one-to-one friendship. That is, <code>Worker&lt;A,B&gt;</code> is a friend of <code>Thing&lt;A,B&gt;</code>. <code>Worker&lt;A,B&gt;</code> is NOT a friend of <code>Thing&lt;A,C&gt;</code>. </p> <p>This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all: </p> <p><a href="http://www.ideone.com/6a1Ih" rel="noreferrer">http://www.ideone.com/6a1Ih</a></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.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      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