| Document number: | P4149R1 | |
|---|---|---|
| Date: | 2026-03-27 | |
| Audience: | EWG, CWG | |
| Reply-to: | Andrzej Krzemieński <akrzemi1 at gmail dot com> Brian Bi <bbi5291 at gmail dot com> |
This paper aims to provide the definition for the term "immediate context". This addresses [US54-100].
The following three pols have been taken on 2026-03-24 during the Croydon meeting.
| SF | F | N | A | SA |
| 0 | 2 | 12 | 10 | 6 |
Verdict: not consensus.
| SF | F | N | A | SA |
| 5 | 12 | 11 | 2 | 1 |
Verdict: consensus.
| SF | F | N | A | SA |
| 1 | 1 | 12 | 10 | 3 |
Verdict: Initially incorrectly declared "no consensus", then corrected to "consensus against".
CWG would like to unify the treatment of noexcept-specifiers, function-contract-specifiers, default arguments, and annotations in order to improve the consistency of the language and the specification. The proposed unified treatment is that the immediate context excludes separately instantiated constructs and includes everything else (other than lambda bodies). To that end, CWG is requesting EWG's consent for the following changes/clarifications. We believe that items 1 and 2 below apply only to the special case of constructs that appear in a non-generic lambda in a SFINAE context (like the return type of a function template).
Default arguments are always subject to separate instantiation, even when they appertain to non-generic lambdas or member functions of local classes. However, in non-generic lambdas and member functions of local classes, that separate instantiation is not deferred; consequently, default arguments are excluded from the immediate context even in these cases. (For local classes, this is not a change in behavior. For non-generic lambdas, the status quo is unclear). For example:
struct X {};
// default argument not used:
template <class T>
auto foo() -> decltype([](T x = T(1)){}(T()));
template <class T>
concept canFoo = requires { foo<T>(); };
constexpr bool b = canFoo<X>; // ???
CWG suggestion: There is no separate instantiation for the default argument in this case. A hard error therefore occurs during overload resolution, even though the default argument isn't used.
Implementation status: GCC currently accepts; Clang and MSVC reject.
noexcept-specifiers on function declarations will be changed so that they are treated the same way as suggested above for default arguments, i.e., to receive separate instantiation always (and thus never be in the immediate context) but have that separate instantiation be performed immediately in the non-generic lambda and local class cases. (The status quo is that noexcept-specifiers of non-generic lambdas and member functions of local classes are not subject to separate instantiation. In the lambda case, Clang and GCC treat them as being in the immediate context.) For example:
template <class T>
auto foo() -> decltype([]() noexcept(noexcept(T() + 1)){ /* ... */ });
template <class T>
concept canFoo = requires { foo<T>(); };
struct X {};
constexpr bool b = canFoo<X>; // ???
Status quo: `b` is initialized to `false`.
Implementation status: Clang and GCC agree, while MSVC gives a hard error.
CWG suggestion: the result should be a hard error because the noexcept-specifier is immediately but separately instantiated.
If this suggestion is rejected, then noexcept-specifiers will be self-consistent (not separately instantiated in the above context + yes in the immediate context) but different from function contract specifiers.
Annotations of templated entities should be instantiated only when needed, similarly to noexcept-specifiers and function contract specifiers, and are therefore never in the immediate context. (CWG has not yet formulated a position as to when, exactly, annotations are considered needed.) Unlike in items 1 and 2, this clarification would affect templated functions in general, not just the lambda edge cases.
On 2026-03-26 during the Croydon meeting, EWG took the following polls.
| SF | F | N | A | SA |
| 3 | 15 | 3 | 0 | 0 |
Verdict: consensus.
| SF | F | N | A | SA |
| 0 | 4 | 7 | 4 | 2 |
Verdict: not consensus.
| SF | F | N | A | SA |
| 2 | 10 | 6 | 0 | 0 |
Verdict: consensus.
CWG asks for consent from EWG for the following changes/clarifications:
The rationale for the above rule is primarily consistency: a "just in time" instantiation rule for annotations would be unlike anything else in the language. The question arose of whether to be consistent with noexcept-specifiers or with contracts. It makes more sense to be consistent with noexcept-specifiers since annotations are a compile-time facility that are not inherently tied to evaluated calls. For simplicity of specification and teachability, parameter annotations should be instantiated at the same time as annotations of functions themselves.
| SF | F | N | A | SA |
| 3 | 17 | 2 | 0 | 0 |
Verdict: consensus.
The proposed wording is relative to [N5032].
Edit [except.spec]/12:
An exception specification is considered to be needed when:
- in an expression, the function is selected by overload resolution ([over.match], [over.over]);
- the function is odr-used ([basic.def.odr]);
- the exception specification is compared [...];
- the function is defined
; or- the function is represented by a reflection; or
- the exception specification is needed for a defaulted function that calls the function. [Note: ...]
The exception specification of a defaulted function is evaluated as described only when needed
; similarly, the noexcept-specifier of a specialization of a templated function is instantiated only when needed.
Edit [temp.decls.general]/3:
A separately instantiated construct of a templated function
Fis a
- default argument,
- noexcept-specifier, or
- function-contract-specifier
of
F.For purposes of name lookup and instantiation,
default argumentsseparately instantiated constructs, type-constraints, and requires-clauses ([temp.pre]), and noexcept-specifiers, of function templates and of member functions of class templatesare considered definitions; eachdefault argumentseparately instantiated construct, type-constraint, or requires-clauseor noexcept-specifieris a separate definition which is unrelated to the templated function definition or to any otherdefault argumentsseparately instantiated constructs, type-constraints, or requires-clauses, or noexcept-specifiers. For the purpose of instantiation, the substatements of a constexpr if statement are considered definitions. For the purpose of name lookup and instantiation, the compound-statement of an expansion-statement is considered a template definition.
Strike note 3 from [temp.inst]/2:
[Note 3: Within a template declaration, a local class or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, noexcept-specifiers, and non-static data member initializers, if any, but not their type-constraints or requires-clauses). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. — end note]
Edit [temp.inst]/3:
[...]
The implicit instantiation of a class template specialization does not cause the implicit instantiation of default arguments or noexcept-specifiers of the class member functions.[...]
Edit [temp.inst]/5:
Unless a function template specialization is a declared specialization, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. A function whose declaration was instantiated from a friend function definition is implicitly instantiated when it is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program.
Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
Add a paragraph before [temp.inst]/12:
The separately instantiated constructs ([temp.decls.general]) of a templated function
Fthat is either
- a member of a local class or
- the function call operator of the closure type of a non-generic lambda-expression
are instantiated when the declaration of
Fis instantiated.
[Note: For the purposes of instantiation, these constructs are still considered separately from the function to which they belong. — end note]
Edit [temp.inst]/12:
Other than as specified above, when
Ifa templated function f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point, except that the scope in which a closure type is declared ([expr.prim.lambda.closure]) — and therefore its associated namespaces — remain as determined from the context of the definition for the default argument. This analysis is called default argument instantiation. The instantiated default argument is then used as the argument of f.
Edit [temp.inst]/13:
[Note: Each default argument is instantiated independently. — end note]
[Example 8: … ]
Edit [temp.inst]/14:
Other than as specified above, the
The noexcept-specifier and function-contract-specifiersseparately instantiated constructs of afunction templatespecialization of a templated function arenot instantiated along with the function declaration; they areinstantiated only when needed ([except.spec], [dcl.contract.func]).IfWhen such aspecifierconstruct isneeded but has not yet beeninstantiated, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in thespecifierconstruct is done as if it were being done as part of instantiating the declaration of the specialization at that point.
Edit [temp.deduct.general]/8 as follows.
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written in the same context using the substituted arguments.
[Note: ... ]
Invalid types and expressions can result in a deduction failure only in the immediate context of the deduction substitution loci. The immediate context of a deduction substitution locus is that deduction substitution locus, excluding bodies of lambda-expressions and separately instantiated constructs.
[Example:
template<typename T> T* fun(T&& v); // #1: the deduction substitution locus is the function type // "function of (rvalue reference to T) returning pointer to T" void fun(...); // #2 void test() { int i; fun(i); // selects #2 (forming the type "pointer to reference to int" fails in #1) }— end example][Note: Separately instantiated constructs are excluded from the immediate contexts even if they are instantiated at the same time. — end note]
[Note 6: The substitution into types and expressions can result in effects such as the instantiation of
classtemplate specializationsand/or function template specializations, the generation of implicitly-defined functions, etc. Such effects are not in the“immediate context”and can result in the program being ill-formed. —end note]
Strike the normative text in [temp.deduct.general]/9, update the note to more concisely express the rationale, and leave the example (demonstrating the interaction of lambdas with SFINAE):
When substituting into a lambda-expression, substitution into its body is not in the immediate context.
[Note 7:
The intent is to avoid requiring implementations to deal with substitution failure involving arbitrary statementsNo statement is ever in the immediate context of a deduction substitution locus.[Example 7: ... —end example]
—end note]