This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
[ 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?).