This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Ready status.
Section: 21.3.6.4 [meta.unary.prop], 21.3.8 [meta.rel] Status: Ready Submitter: Tim Song Opened: 2026-03-05 Last modified: 2026-03-06
Priority: Not Prioritized
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Ready status.
Discussion:
Per 7.7 [expr.const]p23, calls to immediate functions are not immediate invocations,
and therefore are not required to result in constant expressions, if the call occurs in an unevaluated operand.
Currently, some type traits (e.g. is_assignable, is_invocable) specify that the construct at issue is treated as an unevaluated operand,
while others (is_constructible, is_convertible) do not. This seems like a bad state of affairs.
requires expressions
(and implementations). This arguably makes the traits less useful in some contexts where false negatives are tolerable
but false positives are not.
[2026-03-06 LWG telecon; move to Ready]
Proposed resolution:
This wording is relative to N5032.
Modify [tab:meta.unary.prop], Table 54 — Type property predicates as indicated:
Template Condition Preconditions … … … template<class T, class U> struct reference_constructs_from_temporary;Tis a reference type, and the initializationT t(VAL<U>);is well-formed and bindstto a temporary object whose lifetime is extended (6.8.7 [class.temporary]). The full-expression of the variable initialization is treated as an unevaluated operand (7.2.3 [expr.context]). Access checking is performed as if in a context unrelated toTandU. Only the validity of the immediate context of the variable initialization is considered. [Note 5: … — end note][…] template<class T, class U> struct reference_converts_from_temporary;Tis a reference type, and the initializationT t = VAL<U>;is well-formed and bindstto a temporary object whose lifetime is extended (6.8.7 [class.temporary]). The full-expression of the variable initialization is treated as an unevaluated operand (7.2.3 [expr.context]). Access checking is performed as if in a context unrelated toTandU. Only the validity of the immediate context of the variable initialization is considered. [Note 6: … — end note][…] … … …
Modify 21.3.6.4 [meta.unary.prop] p9 as indicated:
-9- The predicate condition for a template specialization
is_constructible<T, Args...>shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet:T t(declval<Args>()...);[Note 7: … — end note]
The full-expression of the variable initialization is treated as an unevaluated operand (7.2.3 [expr.context]). Access checking is performed as if in a context unrelated toTand any of theArgs. Only the validity of the immediate context of the variable initialization is considered. [Note 8: … — end note]
Modify 21.3.8 [meta.rel] p6 as indicated:
-9- The predicate condition for a template specialization
is_convertible<From, To>shall be satisfied if and only if the returnexpressionstatement (8.8.4 [stmt.return]) in the following code would be well-formed, including any implicit conversions to the return type of the function:To test() { return declval<From>(); }[Note 4: … — end note]
Access checking is performed in a context unrelated toToandFrom. The operand of thereturnstatement (including initialization of the returned object or reference, if any) is treated as an unevaluated operand (7.2.3 [expr.context]), and only the validity of its immediate context is considered.Only the validity of the immediate context of the expression of the[Note 5: … — end note]returnstatement (8.8.4 [stmt.return]) (including initialization of the returned object or reference) is considered.