title: Undefined reference to static constexpr, if passed as function parameter pack with O0 (works with higher optimization levels)
body: <p>The following code snippet can only be linked if optimization level was higher than O0:</p>
  <pre class="lang-cpp prettyprint-override"><code>    #include &lt;cstdio&gt;
      #include &lt;utility&gt;
      void vf(std::size_t n, ...) {printf(&quot;%zu\n&quot;, n);}
      template&lt;typename ...ARGS&gt; void vt(ARGS&amp;&amp;... args) {vf( sizeof...(ARGS), std::forward&lt;ARGS&gt;(args)... );}
      struct X {static constexpr int a = 123; X() {vt(a);}};
      int main() {X();}
  </code></pre>
  <p>You can run it here: <a href="http://cpp.sh/3dv7p" rel="nofollow noreferrer">http://cpp.sh/3dv7p</a></p>
  <p>Configuring C++11/14 with O0 will fail with the following linker error:</p>
  <pre><code>/tmp/cc1xC4HI.o: In function `X::X()':
  :(.text._ZN1XC2Ev[_ZN1XC5Ev]+0xd): undefined reference to `X::a'
  collect2: error: ld returned 1 exit status
  </code></pre>
  <p>Choosing O1, O2 or O3 will link successfully and the program execution returns the expected output.</p>
  <h1>Solution</h1>
  <p>It was shown that this problem is not related to the variadic template function. The only question is, if the compiler optimization substituted the <code>static constexpr</code> member during compile time (&gt;O0) or during link time (O0). In the later case, the declaration of <code>X::a</code> also requires some valid definition. This can be done by adding <code>constexpr int X::a;</code> to the above code snippet. The resulting code snippet then will link with any optimization level:</p>
  <pre class="lang-cpp prettyprint-override"><code>    #include &lt;cstdio&gt;
      #include &lt;utility&gt;
      void vf(std::size_t n, ...) {printf(&quot;%zu\n&quot;, n);}
      template&lt;typename ...ARGS&gt; void vt(ARGS&amp;&amp;... args) {vf( sizeof...(ARGS), std::forward&lt;ARGS&gt;(args)... );}
      struct X {static constexpr int a = 123; X() {vt(a);}};
      constexpr int X::a;
      int main() {X();}
  </code></pre>
  <p>Please notice that with <code>static constexpr</code> members it is necessary to initialize during declaration, to have complete type, and not during definition.</p>
  <p>To let the compiler substitute already during compile-time, also with O0, no reference to <code>X::a</code> should be passed. That's why this snippet will also successfully link with O0, even if it has no definition of <code>X::a</code>:</p>
  <pre class="lang-cpp prettyprint-override"><code>    #include &lt;cstdio&gt;
      #include &lt;utility&gt;
      void vf(std::size_t n, ...) {printf(&quot;%zu\n&quot;, n);}
      template&lt;typename ...ARGS&gt; void vt(ARGS... args) {vf( sizeof...(ARGS), std::forward&lt;ARGS&gt;(args)... );}
      struct X {static constexpr int a = 123; X() {vt(a);}};
      int main() {X();}
  </code></pre>