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

2025-04-13


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 evaluatedunless it is an unevaluated operand ( Clause 7 [expr]) or a subexpression thereof.if and only if

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-usedunless 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?).



close