Title
Some type-completeness constraints of traits are overspecified
Status
open
Section
[meta.type.synop]
Submitter
Daniel Krügler

Created on 2017-03-02.00:00:00 last changed 3 months ago

Messages

Date: 2024-08-21.17:09:48

Proposed resolution:

This wording is relative to n4988.

  1. In [meta.unary.prop] Table 51, change the Preconditions text for `is_constructible`, `is_trivially_constructible`, `is_nothrow_constructible`, `is_convertible`, and `is_nothrow_convertible`, as indicated.
    TemplateConditionPreconditions
    template<class T, class... Args>
    struct is_constructible;
    For a function type `T` or for a cv `void` type `T`, is_constructible_v<T, Args...> is `false`, otherwise see below . Either `T` is a reference type and `Args` contains a single type and that type is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class T, class... Args>
    struct is_trivially_constructible;
    is_constructible_v<T, Args...> is `true` and the variable definition for `is_constructible`, as defined below, is known to call no operation that is not trivial ([basic.types.general], [special]). Either `T` is a reference type and `Args` contains a single type and that type is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class T, class... Args>
    struct is_nothrow_constructible;
    is_constructible_v<T, Args...> is `true` and the variable definition for `is_constructible`, as defined below, is known not to throw any exceptions ([expr.unary.noexcept]). Either `T` is a reference type and `Args` contains a single type and that type is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
  2. In [meta.rel] Table 53, change the Comments text for `is_convertible` and `is_nothrow_convertible` as indicated.
    TemplateConditionComments
    template<class From, class To>
    struct is_convertible;
    see below Either `To` is a reference type and `From` is similar ([conv.qual]) to remove_reference_t<To>, or `From` and `To` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class From, class To>
    struct is_nothrow_convertible;
    is_convertible_v<From, To> is `true` and the conversion, as defined by `is_convertible`, is known not to throw any exceptions ([expr.unary.noexcept]). Either `To` is a reference type and `From` is similar ([conv.qual]) to remove_reference_t<To>, or `From` and `To` shall be complete types, cv `void`, or arrays of unknown bound.
Date: 2024-08-15.00:00:00

[ 2024-08-21; Jonathan provides improved wording ]

Following on LWG telecon review, change "Args contains a single type that is similar" to "Args contains a single type and that type is similar".

Date: 2024-05-15.00:00:00

[ 2024-05-09; Jonathan provides wording ]

We could also relax the type completeness requirements for `reference_converts_from_temporary` and `reference_constructs_from_temporary`, as the result is always false if the first type is a non-reference, so we don't need complete types in that case. This doesn't seem important to support, but if we wanted to then we could say:

Either `T` is not a reference type, or `T` and `U` shall be a complete type complete types, cv `void`, or an arrayarrays of unknown bound.

This wording is relative to n4981.

  1. In [meta.unary.prop] Table 51, change the Preconditions text for `is_constructible`, `is_trivially_constructible`, `is_nothrow_constructible`, `is_convertible`, and `is_nothrow_convertible`, as indicated.
    TemplateConditionPreconditions
    template<class T, class... Args>
    struct is_constructible;
    For a function type `T` or for a cv `void` type `T`, is_constructible_v<T, Args...> is `false`, otherwise see below . Either `T` is a reference type and `Args` contains a single type that is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class T, class... Args>
    struct is_trivially_constructible;
    is_constructible_v<T, Args...> is `true` and the variable definition for `is_constructible`, as defined below, is known to call no operation that is not trivial ([basic.types.general], [special]). Either `T` is a reference type and `Args` contains a single type that is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class T, class... Args>
    struct is_nothrow_constructible;
    is_constructible_v<T, Args...> is `true` and the variable definition for `is_constructible`, as defined below, is known not to throw any exceptions ([expr.unary.noexcept]). Either `T` is a reference type and `Args` contains a single type that is similar ([conv.qual]) to remove_reference_t<T>, or `T` and all types in the template parameter pack `Args` shall be complete types, cv `void`, or arrays of unknown bound.
  2. In [meta.rel] Table 53, change the Comments text for `is_convertible` and `is_nothrow_convertible` as indicated.
    TemplateConditionComments
    template<class From, class To>
    struct is_convertible;
    see below Either `To` is a reference type and `From` is similar ([conv.qual]) to remove_reference_t<To>, or `From` and `To` shall be complete types, cv `void`, or arrays of unknown bound.
    template<class From, class To>
    struct is_nothrow_convertible;
    is_convertible_v<From, To> is `true` and the conversion, as defined by `is_convertible`, is known not to throw any exceptions ([expr.unary.noexcept]). Either `To` is a reference type and `From` is similar ([conv.qual]) to remove_reference_t<To>, or `From` and `To` shall be complete types, cv `void`, or arrays of unknown bound.
Date: 2020-02-13.15:35:37

[ 2020-02 Prague Thursday issue discussion ]

Two of the issues (2797 and 3022) had been resolved by the acceptance of P1285R0.

Date: 2018-08-22.12:55:05

[ 2018-08 Batavia Monday issue discussion ]

Issues 2797, 2939, 3022, and 3099 are all closely related. Walter to write a paper resolving them.

Date: 2017-03-15.00:00:00

[ 2017-03-04, Kona ]

Set priority to 2. Is related to 2797, but really needs an audit of the type traits.

Date: 2017-03-02.00:00:00

LWG 2797 (RU 2) suggests that certain type-traits should be required to diagnose violations of their pre-conditions. The basic idea is founded and I see no problems for requiring this for the mentioned traits alignment_of or is_base_of, for example. But if we want to require this diagnostics for some other traits, such as is_convertible, is_constructible (and friends), or is_callable (and possibly some others), we really should be sure that our current requirements are OK.

Unfortunately, there exists some cases, where we currently overspecify imposing complete type requirements where they are not actually required. For example, for the following situation the answer of the trait could be given without ever needing the complete type of X:

struct X; // Never defined

static_assert(std::is_convertible_v<X, const X&>);

Unfortunately we cannot always allow incomplete types, because most type constructions or conversions indeed require a complete type, so generally relaxing the current restrictions is also not an option.

The core language has a solution for this "small" gap of situations, where the response of the compiler might depend on type completeness: Undefined behaviour. So, I believe we need a somewhat more detailled form to express the intend here. Informally, I would suggest that the program should only be ill-formed in the situation described by LWG 2797, if there exists the possibility that the compiler would require complete types for the considered operation. The example shown above, std::is_convertible_v<X, const X&>, would never require the need to complete X, so here no violation should exist.

The presented example might seem a tiny one, but the Standard Library type traits are extreme fundamental tools and we should try to not give the impression that an approximate rule of the current type constraints breaks reasonable code.

It is correct, that above example has currently undefined behaviour due to the breakage of pre-conditions, therefore this issue suggests to fix the current situation before enforcing a diagnostic for such valid situations.

History
Date User Action Args
2024-08-21 21:45:32adminsetstatus: new -> open
2024-08-21 17:09:48adminsetmessages: + msg14333
2024-05-09 14:20:05adminsetmessages: + msg14130
2024-05-09 14:20:05adminsetmessages: + msg14129
2020-02-13 15:35:37adminsetmessages: + msg11069
2018-08-22 12:55:05adminsetmessages: + msg10093
2017-03-14 03:14:09adminsetmessages: + msg9119
2017-03-02 00:00:00admincreate