Variadic template only compiles when forward declared : <p>I have a variadic template that inherits from all template arguments:</p>

<pre><code>template &lt;typename... Ts&gt;
struct derived : Ts...
{
};
</code></pre>

<p>I would also like to have a facility for expressing the type of "existing <code>derived</code> with added template arguments". My attempt at this is:</p>

<pre><code>// Do not ODR-use (goes in namespace impl or similar)!
template&lt;class ... NewInputs, class ... ExistingInputs&gt;
auto addedHelper(const derived&lt;ExistingInputs...&gt;&amp;)
    -&gt; derived&lt;ExistingInputs..., NewInputs...&gt;;

template&lt;class ExistingInput, class ... NewInputs&gt;
using Added = decltype(addedHelper&lt;NewInputs...&gt;(std::declval&lt;ExistingInput&gt;()));
</code></pre>

<p>As a simple example, <code>Added&lt;derived&lt;A, B&gt;, C&gt;</code> should be <code>derived&lt;A, B, C&gt;</code>. I use the helper function for template argument deduction of the first parameter pack.</p>

<p>My problem: For some reason, I can use this successfully with incomplete types if <code>derived</code> has been forward declared, but <strong>not</strong> if it was defined.</p>

<p><strong>Why does this code <a href="https://godbolt.org/z/ePhquh" rel="noreferrer">not compile</a>:</strong></p>

<pre><code>#include &lt;utility&gt;

template &lt;typename... Ts&gt;
struct derived : Ts...
{};

template&lt;class ... NewInputs, class ... ExistingInputs&gt;
auto addedHelper(const derived&lt;ExistingInputs...&gt;&amp;)
    -&gt; derived&lt;ExistingInputs..., NewInputs...&gt;;

template&lt;class ExistingInput, class ... NewInputs&gt;
using Added = decltype(addedHelper&lt;NewInputs...&gt;(std::declval&lt;ExistingInput&gt;()));


struct A;
struct B;
struct C;

// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived&lt;A, B&gt; in) -&gt; Added&lt;decltype(in), C&gt;;


struct A {};
struct B {};
struct C {};

void foo()
{
    auto abc = test({});

    static_assert(std::is_same_v&lt;decltype(abc), derived&lt;A, B, C&gt;&gt;, "Pass");
}
</code></pre>

<p><strong>Whereas this code <a href="https://godbolt.org/z/qow3Kb" rel="noreferrer">does compile</a>:</strong></p>

<pre><code>#include &lt;utility&gt;

template &lt;typename... Ts&gt;
struct derived;


template&lt;class ... NewInputs, class ... ExistingInputs&gt;
auto addedHelper(const derived&lt;ExistingInputs...&gt;&amp;)
    -&gt; derived&lt;ExistingInputs..., NewInputs...&gt;;

template&lt;class ExistingInput, class ... NewInputs&gt;
using Added = decltype(addedHelper&lt;NewInputs...&gt;(std::declval&lt;ExistingInput&gt;()));


struct A;
struct B;
struct C;

// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived&lt;A, B&gt; in) -&gt; Added&lt;decltype(in), C&gt;;


template &lt;typename... Ts&gt;
struct derived : Ts...
{};


struct A {};
struct B {};
struct C {};

void foo()
{
    auto abc = test({});

    static_assert(std::is_same_v&lt;decltype(abc), derived&lt;A, B, C&gt;&gt;, "Pass");
}
</code></pre>

<p>For convenience, here are both cases at once (comment in/out <code>#define FORWARD_DECLARED</code>): <a href="https://godbolt.org/z/7gM52j" rel="noreferrer">https://godbolt.org/z/7gM52j</a></p>

<p>I do not understand how code could possibly become illegal by replacing a forward declaration by the respective definition (which would otherwise just come later).</p>
