Title
Type traits have inconsistent interactions with immediate functions
Status
ready
Section
[meta.unary.prop] [meta.rel]
Submitter
Tim Song

Created on 2026-03-05.00:00:00 last changed yesterday

Messages

Date: 2026-03-06.17:39:50

Proposed resolution:

This wording is relative to N5032.

  1. Modify [tab:meta.unary.prop], Table 54 — Type property predicates as indicated:

    TemplateConditionPreconditions
    
    template<class T, class U>
    struct reference_constructs_from_temporary;
    `T` is a reference type, and the initialization T t(VAL<U>); is well-formed and binds `t` to a temporary object whose lifetime is extended ([class.temporary]). The full-expression of the variable initialization is treated as an unevaluated operand ([expr.context]). Access checking is performed as if in a context unrelated to `T` and `U`. 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;
    `T` is a reference type, and the initialization T t = VAL<U>; is well-formed and binds `t` to a temporary object whose lifetime is extended ([class.temporary]). The full-expression of the variable initialization is treated as an unevaluated operand ([expr.context]). Access checking is performed as if in a context unrelated to `T` and `U`. Only the validity of the immediate context of the variable initialization is considered. [Note 6: … — end note] […]
  2. Modify [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 variable `t`:

    T t(declval<Args>()...);
    

    [Note 7: … — end note]

    The full-expression of the variable initialization is treated as an unevaluated operand ([expr.context]). Access checking is performed as if in a context unrelated to `T` and any of the `Args`. Only the validity of the immediate context of the variable initialization is considered.

    [Note 8: … — end note]

  3. Modify [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 return expressionstatement ([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 to `To` and `From`. The operand of the `return` statement (including initialization of the returned object or reference, if any) is treated as an unevaluated operand ([expr.context]), and only the validity of its immediate context is considered. Only the validity of the immediate context of the expression of the `return` statement ([stmt.return]) (including initialization of the returned object or reference) is considered.

    [Note 5: … — end note]

Date: 2026-03-06.00:00:00

[ 2026-03-06 LWG telecon; move to Ready ]

Date: 2026-03-05.00:00:00

Per [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.

The wording below makes everything unevaluated (and hence not check for constant-ness) to match the behavior of `requires` expressions (and implementations). This arguably makes the traits less useful in some contexts where false negatives are tolerable but false positives are not.

History
Date User Action Args
2026-03-06 17:39:50adminsetmessages: + msg16013
2026-03-06 17:39:50adminsetstatus: new -> ready
2026-03-06 10:40:28adminsetmessages: + msg16007
2026-03-05 00:00:00admincreate