Thanks to new wording in C++20, it is possible to give a definitive answer to your question. In the comments, Igor Tandetnik mentioned the relevant paragraph in C++17, namely [temp.inst]/3. In C++20, it is [temp.inst]/4, which has some new relevant wording that I have bolded:
Unless a member of a class template or a member template is a declared specialization, the specialization of
the member is implicitly instantiated when the specialization is referenced in a context that requires the
member definition to exist or if the existence of the definition of the member affects the semantics of the
program; in particular, the initialization (and any associated side effects) of a static data member does not
occur unless the static data member is itself used in a way that requires the definition of the static data
member to exist.
Later in the same section, paragraph 8:
The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function is needed for constant evaluation by an expression (7.7), even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition.
In short, if the alias-declaration using DummyType = Dummy<flag>;
is instantiated, then the static data member flag
is needed for constant evaluation, therefore it is instantiated.
Informally, "needed for constant evaluation" refers to certain situations where a variable or function is not odr-used, but the way it is used in constant evaluation still requires its definition.
Formally, the definition of "needed for constant evaluation" is given in [expr.const]/15:
An expression or conversion is potentially constant evaluated if it is:
- a manifestly constant-evaluated expression,
- a potentially-evaluated expression (6.3),
- an immediate subexpression of a braced-init-list,
- an expression of the form
&
cast-expression that occurs within a templated entity, or
- a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.
A function or variable is needed for constant evaluation if it is:
- a constexpr function that is named by an expression (6.3) that is potentially constant evaluated, or
- a variable whose name appears as a potentially constant evaluated expression that is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type.
"Manifestly constant-evaluated" is defined in p14 of that section:
An expression or conversion is manifestly constant-evaluated if it is: [...] a constant-expression, or [...] [Note 7: A manifestly constant-evaluated expression is evaluated even in an unevaluated operand. — end note]
"constant-expression" is a grammar production that is used in various contexts to denote a conditional-expression that must be a constant expression. We can check the grammar for simple-template-id (which is what Dummy<flag>
is):
simple-template-id :
template-name <
template-argument-list(opt) >
[...]
template-argument-list :
template-argument ...
(opt)
template-argument-list ,
template-argument ...
(opt)
template-argument :
constant-expression
type-id
id-expression
Here, id-expression refers to a template template parameter. In using DummyType = Dummy<flag>;
, flag
is an argument for a non-type template parameter, so it is a constant-expression.
Since the expression flag
is a manifestly constant-evaluated expression, it is a potentially constant-evaluated expression. The variable flag
's name "appears as a potentially constant evaluated expression" and it's a variable of reference type, so it is needed for constant evaluation.
Note that the concept of "needed for constant evaluation" was introduced by P0589 to resolve CWG 1581. This was voted as a DR, so its resolution is retroactive. The concepts of "needed for constant evaluation" and "manifestly constant-evaluated" always needed to be in C++; their absence led to issues like the one in this question.