This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

2336. is_trivially_constructible/is_trivially_assignable traits are always false

Section: 21.3.5.4 [meta.unary.prop] Status: C++17 Submitter: Daniel Krügler Opened: 2013-10-01 Last modified: 2017-07-30

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with C++17 status.

Discussion:

In 21.3.5.4 [meta.unary.prop] we have traits to allow testing for triviality of specific operations, such as is_trivially_constructible and is_trivially_assignable (and their derived forms), which are specified in terms of the following initialization and assignment, respectively:

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

declval<T>() = declval<U>()

The wording that describes the way how triviality is deduced, is in both cases of the same form:

[… ] and the variable definition/assignment, as defined by is_constructible/is_assignable, is known to call no operation that is not trivial (3.9, 12).

The problematic part of this wording is that both definitions are specified in terms of an "object construction" function create or declval, respectively, (The former being a conceptual function, the latter being a library function), but for none of these functions we can assume that they could be considered as trivial — only special member functions can have this property and none of these is one. This problem became obvious, when the similar issue LWG 2298 in regard to is_nothrow_constructible was opened.

A possible approach to solve this specification problem is to make a blanket statement for sub-clause 21.3.5.4 [meta.unary.prop] that these helper functions are considered trivial for the purpose of defining these traits.

Using this kind of wording technique can also be used to get rid of the additional helper function template create, which is currently needed for the is_convertible and the is_constructible traits, because both traits are specified in terms of contexts where technically the corresponding "object construction" function would be considered as odr-used. This is problematic, because these traits are defined in terms of well-formed code and odr-using declval would make the program ill-formed (see 22.2.6 [declval]). So extending above blanket statement to consider std::declval<T>() as not odr-used in the context of the corresponding trait definition would allow for replacing create by declval.

[2015-05, Lenexa]

STL: would you consider moving the change to 20.10 as editorial or are you uncomfortable with it?
JW: this sounds a viable editorial change
VV: I guarantee you that moving it doesn't change anything
MC: how about this: we move it to Ready as is and if we conclude moving it is editorial we can do it and if not open an issue
STL: I would like to guarantee that the lifting happens
JW: I do that! If it goes in I move it up
MC: move to Ready: in favor: 15, opposed: 0, abstain: 1

Proposed resolution:

This wording is relative to N3936.

  1. Add a new paragraph after 21.3.5.4 [meta.unary.prop] p3 as indicated: [Editorial note: The first change in 21.3.5.4 [meta.unary.prop] p3 is recommended, because technically a Clause is always a "main chapter" — such as Clause 20 — but every child of a Clause or sub-clause is a sub-clause]

    […]

    -3- For all of the class templates X declared in this Clausesub-clause, instantiating that template with a template-argument that is a class template specialization may result in the implicit instantiation of the template argument if and only if the semantics of X require that the argument must be a complete type.

    -?- For the purpose of defining the templates in this sub-clause, a function call expression declval<T>() for any type T is considered to be a trivial (6.8 [basic.types], 11.4.4 [special]) function call that is not an odr-use (6.3 [basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of 22.2.6 [declval].

    […]

  2. Modify 21.3.5.4 [meta.unary.prop] p7 as indicated:

    -7- Given the following function prototype:

    template <class T>
      typename add_rvalue_reference<T>::type create();
    

    tThe 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(createdeclval<Args>()...);
    

    […]

  3. Add a new paragraph after 21.3.7 [meta.rel] p2 as indicated: [Editorial note: Technically we don't need the guarantee of "a trivial function call" for the type relationship predicates at the very moment, but it seems more robust and consistent to have the exact same guarantee here as well]

    […]

    -2- […]

    -?- For the purpose of defining the templates in this sub-clause, a function call expression declval<T>() for any type T is considered to be a trivial (6.8 [basic.types], 11.4.4 [special]) function call that is not an odr-use (6.3 [basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of 22.2.6 [declval].

    […]

  4. Modify 21.3.7 [meta.rel] p4 as indicated:

    -4- Given the following function prototype:

    template <class T>
      typename add_rvalue_reference<T>::type create();
    

    tThe 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-formed, including any implicit conversions to the return type of the function:

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

    […]