Title
When is an instantiation required?
Status
cd5
Section
13.9.2 [temp.inst]
Submitter
Jason Merrill

Created on 2011-08-18.00:00:00 last changed 16 months ago

Messages

Date: 2023-06-15.00:00:00

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

Date: 2023-07-02.20:51: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.)

History
Date User Action Args
2023-07-02 20:51:26adminsetmessages: + msg7351
2023-07-02 20:51:26adminsetstatus: open -> cd5
2011-08-18 00:00:00admincreate