*This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21
Core Issues List revision 115a.
See http://www.open-std.org/jtc1/sc22/wg21/ for the official
list.*

2024-07-24

#### 1378.
When is an instantiation required?

**Section: **13.9.2 [temp.inst]
**Status: **CD5
**Submitter: **Jason Merrill
**Date: **2011-08-18

[ Resolved by P0859R0, approved in November, 2017. ]

A template instantiation can be “required” without
there being a need for it at link time if it can appear in a
constant expression:

template <class T> struct A {
static const T t;
};
template <class T> const T A<T>::t = 0;
template <int I> struct B { };
int a = sizeof(B<A<int>::t>);
template <class T> constexpr T f(T t) { return t; }
int b = sizeof(B<f(42)>);

It seems like it might be useful to define a term other than odr-used
for this sort of use, which is like odr-used but doesn't depend on
potentially evaluated context or lvalue-rvalue conversions.

__Nikolay Ivchenkov:__

Another possibility would be to introduce the extension
described in the closed issue 1272 and
then change 6.3 [basic.def.odr] paragraph 2 as follows:

An expression `E` is *potentially
evaluated* ~~unless it is an unevaluated operand (
Clause 7 [expr]) or a subexpression thereof.~~
if and only if

`E` is a full-expression, or

`E` appears in a context where a constant expression
is required, or

`E` is a direct subexpression of a potentially-evaluated
expression and `E` is not an unevaluated operand.

An expression `S` is a *direct subexpression* of an
expression `E` if and only if `S` and `E`
are different expressions, `S` is a subexpression of
`E`, and there is no expression `X` such that
`X` differs from both `S` and `E`,
`S` is a subexpression of `X`, and `X` is a
subexpression of `E`. A variable whose name appears
as a potentially-evaluated expression is *odr-used*
~~unless it is an object that satisfies the requirements for
appearing in a constant expression (7.7 [expr.const])
and the lvalue-to-rvalue conversion (4.1) is immediately
applied~~...

[*Example:*

template <class T> struct X {
static int const m = 1;
static int const n;
};
template <class T> int const X<T>::n = 2;
int main() {
// X<void>::m is odr-used,
// X<void>::m is defined implicitly
std::cout << X<void>::m << std::endl;
// X<void>::n is odr-used,
// X<void>::n is defined explicitly
std::cout << X<void>::n << std::endl;
// OK (issue 712 is not relevant here)
std::cout << (1 ? X<void>::m : X<void>::n) << std::endl;
}

(See also issues 712 and
1254.)

**Additional notes (June, 2023)**

This was addressed by the introduction of "needed for constant
evaluation" in P0859R0 (Core Issue 1581: When are constexpr member
functions defined?).