2290. Top-level "SFINAE"-based constraints should get a separate definition in Clause 17

Section: 23.15 [meta] Status: Open Submitter: Daniel Krügler Opened: 2013-09-02 Last modified: 2016-02-10

Priority: 3

View other active issues in [meta].

View all other issues in [meta].

View all issues with Open status.

Discussion:

The current library specification uses at several places wording that is intended to refer to core language template deduction failure at the top-level of expressions (aka "SFINAE"), for example:

The expression declval<T>() = declval<U>() is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to T and U. Only the validity of the immediate context of the assignment expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

Similar wording can be found in the specification of result_of, is_constructible, and is_convertible, being added to resolve an NB comment by LWG 1390 and 1391 through N3142.

This wording is necessary to limit speculative compilations needed to implement these traits, but it is also lengthy and repetitive.

[2014-05-19, Daniel suggests a descriptive term]

constrictedly well-formed expression:

An expression e depending on a set of types A1, ..., An which is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to A1, ..., An. Only the validity of the immediate context of e is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

[2014-05-20, Richard and Jonathan suggest better terms]

Richard suggested "locally well-formed"

Jonathan suggested "contextually well-formed" and then "The expression ... is valid in a contrived argument deduction context"

[2014-06-07, Daniel comments and improves wording]

The 2014-05-19 suggestion did only apply to expressions, but there are two important examples that are not expressions, but instead are involving an object definition (std::is_constructible) and a function definition (std::is_convertible), respectively, instead. Therefore I suggest to rephrase the usage of "expression" into "program construct" in the definition of Jonathan's suggestion of "valid in a contrived argument deduction context".

I would like to point out that given the new definition of "valid in a contrived argument deduction context", there are several other places of the Library specification that could take advantage of this wording to improve the existing specification, such as 23.14.13.2 [func.wrap.func] p2, most functions in 23.10.9.2 [allocator.traits.members], and the **Insertable, EmplaceConstructible, and Erasable definitions in 26.2.1 [container.requirements.general], but given that these are not fully described in terms of the aforementioned wording yet, I would recommend to fix them by a separate issue once the committee has agreed on following the suggestion presented by this issue.

[2015-05-05 Lenexa: Move to Open]

...

MC: I think we like the direction but it isn't quite right: it needs some work

JW: I'm prepared to volunteer to move that further, hopefully with the help of Daniel

Roger Orr: should this be Core wording because it doesn't really have anything to do with libraries - the term could then just be used here

AM: Core has nothing to deal with that, though

HT: it seems there is nothing to imply that allows dropping out with an error - maybe that's a separate issue

MC: I'm not getting what you are getting at: could you write an issue? - any objection to move to Open?

...

Proposed resolution:

This wording is relative to N3936.

  1. Add the following new definition to 20.3 [definitions] as indicated:

    valid in a contrived argument deduction context [defns.valid.contr.context]

    A program construct c depending on a set of types A1, ..., An, and treated as an unevaluated operand (Clause 5) when c is an expression, which is well-formed. Access checking is performed as if in a context unrelated to A1, ..., An. Only the validity of the immediate context (17.9.2 [temp.deduct]) of c is considered. [Note: The compilation of c can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note].

  2. Change Table 49 ("Type property predicates") as indicated:

    Table 49 — Type property predicates
    Template Condition Preconditions
    template <class T, class U>
    struct is_assignable;
    The expression declval<T>() =
    declval<U>()
    is valid in a
    contrived argument deduction context
    ([defns.valid.contr.context]) for types
    T and U.
    well-formed when treated
    as an unevaluated operand
    (Clause 5). Access
    checking is performed as if
    in a context unrelated to T
    and U. Only the validity of
    the immediate context of
    the assignment expression
    is considered. [Note: The
    compilation of the
    expression can result in
    side effects such as the
    instantiation of class
    template specializations
    and function template
    specializations, the
    generation of
    implicitly-defined
    functions, and so on. Such
    side effects are not in the
    "immediate context" and
    can result in the program
    being ill-formed. — end
    note]
    […]
  3. Change 23.15.4.3 [meta.unary.prop] p7 as indicated:

    -7- Given the following function prototype:

    template <class T>
      add_rvalue_reference_t<T> create() noexcept;
    

    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 would be valid in a contrived argument deduction context ([defns.valid.contr.context]) for types T and Args...:

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

    [Note: These tokens are never interpreted as a function declaration. — end note] 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: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

  4. Change Table 57 ("Other transformations") as indicated:

    Table 57 — Other transformations
    Template Condition Comments
    template <class Fn, class... ArgTypes>
    struct result_of<Fn(ArgTypes...)>;
    […] If the expression
    INVOKE(declval<Fn>(),
    declval<ArgTypes>()...)
    is
    valid in a contrived argument deduction
    context ([defns.valid.contr.context]) for types
    Fn and ArgTypes...
    well
    formed when treated as an
    unevaluated operand (Clause 5)
    , the
    member typedef type shall name the
    type
    decltype(INVOKE(declval<Fn>(),
    declval<ArgTypes>()...))
    ;
    otherwise, there shall be no member
    type. Access checking is performed as
    if in a context unrelated to Fn and
    ArgTypes. Only the validity of the
    immediate context of the expression is
    considered. [Note: The compilation of
    the expression can result in side
    effects such as the instantiation of
    class template specializations and
    function template specializations, the
    generation of implicitly-defined
    functions, and so on. Such side effects
    are not in the "immediate context"
    and can result in the program being
    ill-formed. — end note]
  5. Change 23.15.6 [meta.rel] p4 as indicated:

    -4- Given the following function prototype:

    template <class T>
      add_rvalue_reference_t<T> create() noexcept;
    

    the predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and only if the return expression in the following code would be well-formedvalid in a contrived argument deduction context ([defns.valid.contr.context]) for types To and From, including any implicit conversions to the return type of the function:

    To test() {
      return create<From>();
    }
    

    [Note: This requirement gives well defined results for reference types, void types, array types, and function types. — end note] Access checking is performed as if in a context unrelated to To and From. Only the validity of the immediate context of the expression of the return-statement (including conversions to the return type) is considered. [Note: The evaluation of the conversion can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]