Note that there are some explanatory texts on larger screens.

plurals
  1. POC++ linking and template specializations
    primarykey
    data
    text
    <p>I'm studying the behavior of the C++ linker with respect to template specializations. I'm using Microsoft Visual C++ 2010 for these experiments. I don't know if the behavior is the same with other toolchains (e.g. gcc).</p> <p>Here's a first code snippet:</p> <pre class="lang-cpp prettyprint-override"><code>// bar.cpp template &lt;typename T&gt; int foo() { return 1; } int bar() { return foo&lt;double&gt;(); } // main.cpp template &lt;typename T&gt; int foo() { return 1; } template &lt;&gt; int foo&lt;double&gt;() { return 2; } int bar(); int main() { const int x = bar(); const int y = foo&lt;double&gt;(); // doesn't link } </code></pre> <p>Expectedly, this code doesn't link because <code>foo&lt;double&gt;()</code> has multiple definitions as it gets instantiated once in <em>bar.cpp</em> and once in <em>main.cpp</em> (via specialization). We would then expect, <em>if this program would link</em>, that <code>bar()</code> and <code>main()</code> would use distinct instantiations of <code>foo()</code> such that at the end we would have x&nbsp;==&nbsp;1 and y&nbsp;==&nbsp;2.</p> <p>Let's fix the link error by declaring the specialization of <code>foo&lt;double&gt;()</code> as <code>static</code>:</p> <pre class="lang-cpp prettyprint-override"><code>// bar.cpp template &lt;typename T&gt; int foo() { return 1; } int bar() { return foo&lt;double&gt;(); } // main.cpp template &lt;typename T&gt; int foo() { return 1; } template &lt;&gt; static int foo&lt;double&gt;() { return 2; } // note: static int bar(); int main() { const int x = bar(); // x == 1 const int y = foo&lt;double&gt;(); // y == 2 } </code></pre> <p>We now have x&nbsp;==&nbsp;1 and y&nbsp;==&nbsp;2, as we expected. (Note: we <em>must</em> use the <code>static</code> keyword here: an anonymous namespace won't do since we can't specialize a template function in a different namespace than its declaration.)</p> <p>Now, the use of the <code>static</code> keyword is rather unintuitive. Typically, the specialization <code>foo&lt;double&gt;()</code> would reside somewhere in a header file, and thus would be marked as inline, like in the following snippet:</p> <pre class="lang-cpp prettyprint-override"><code>// bar.cpp template &lt;typename T&gt; int foo() { return 1; } int bar() { return foo&lt;double&gt;(); } // main.cpp template &lt;typename T&gt; int foo() { return 1; } template &lt;&gt; inline int foo&lt;double&gt;() { return 2; } // note: inline int bar(); int main() { const int x = bar(); // x == 2 const int y = foo&lt;double&gt;(); // y == 2 } </code></pre> <p>This code now links properly and when we run it we get x&nbsp;==&nbsp;2 and y&nbsp;==&nbsp;2. <strong>This is the bit I find surprising: why is there a single definition of <code>foo&lt;double&gt;()</code>? What is the meaning of <code>inline</code> in this code?</strong></p> <p>A last snippet:</p> <pre class="lang-cpp prettyprint-override"><code>// bar.cpp template &lt;typename T&gt; int foo() { return 1; } int bar() { return foo&lt;double&gt;(); } // main.cpp template &lt;typename T&gt; int foo() { return 1; } template &lt;&gt; inline int foo&lt;double&gt;() { return 2; } // note: inline int bar(); int main() { const int x = bar(); // x == 1 // const int y = foo&lt;double&gt;(); // note: commented out } </code></pre> <p>This case is actually not surprising: the specialization of <code>foo&lt;double&gt;()</code> is no longer instantiated in <em>main.cpp</em> (although the declaration is still there), so the only instantiation remaining is the one in <em>bar.cpp</em>.</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