This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


2355. Deducing noexcept-specifiers

Section: 13.10.3.6  [temp.deduct.type]     Status: CD6     Submitter: John Spicer     Date: 2017-09-06

[Accepted at the July, 2022 meeting.]

The list of deducible forms in 13.10.3.6 [temp.deduct.type] paragraph 8 does not include the ability to deduce the value of the constant in a noexcept-specifier, although implementations appear to allow it.

Notes from the April, 2018 teleconference:

Although this appears to be an obvious omission, CWG felt that EWG should weigh in on whether this capability should be supported or not.

EWG guidance (January, 2021):

Modify the Standard such that the value of a constant in a noexcept-specifier can be deduced. See vote.

Proposed resolution (June, 2022):

  1. Change 13.10.3.6 [temp.deduct.type] paragraph 3 as follows:

  2. A given type P can be composed from a number of other types, templates, and non-type values:

  3. Add the following to Example 3 in 13.10.3.6 [temp.deduct.type] paragraph 7:

  4. Here is an example where two template arguments are deduced from a single function parameter/argument pair...

    Here is an example where the exception specification of a function type is deduced:

      template <bool E> void f1(void (*)() noexcept(E));
      template<bool> struct A { };
      template<bool B> void f2(void (*)(A<B>) noexcept(B));
    
      void g1();
      void g2() noexcept;
      void g3(A<true>);
    
      void h() {
        f1(g1);    // OK: E is false
        f1(g2);    // OK: E is true
        f2(g3);    // error: B deduced as both true and false
      }
    

    Here is an example where a qualification conversion applies...

  5. Change 13.10.3.6 [temp.deduct.type] paragraph 8 as follows:

  6. A template type argument T, a template template argument TT, or a template non-type argument i can be deduced if P and A have one of the following forms:

    where (T) represents a parameter-type-list (9.3.4.6 [dcl.fct]) where at least one parameter type contains a T, and () represents a parameter-type-list where no parameter type contains a T.

    [Note: If a type matches such a form but contains no Ts, is, or TTs, deduction is not possible. —end note]

    Similarly, <T> represents template argument lists where at least one argument contains a T, <i> represents template argument lists where at least one argument contains an i and <> represents template argument lists where no argument contains a T or an i.

  7. Add the following as a new paragraph following 13.10.3.6 [temp.deduct.type] paragraph 14:

  8. The type of N in the type T[N] is std::size_t. [Example 9: ... —end example]

    The type of B in the noexcept-specifier noexcept(B) of a function type is bool.
    [Example:

      template<bool> struct A { };
      template<auto> struct B;
      template<auto X, void (*F)() noexcept(X)> struct B<F> {
        A<X> ax;
      };
      void f_nothrow() noexcept;
      B<f_nothrow> bn;   // OK: type of X deduced as bool
    

    end example]

  9. Change 13.10.3.6 [temp.deduct.type] paragraph 19 as follows:

  10. If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails. If P has a form that contains [i], and if the type of i is not an integral type, deduction fails.131 If P has a form that includes noexcept(i) and the type of i is not bool, deduction fails.
    [Example 12: ...
  11. Add the following as a new section preceding C.2.7 [diff.cpp20.library]:

  12. C.1.4 Clause 13: templates [diff.cpp20.temp]

    Affected subclause: 13.10.3.6 [temp.deduct.type]
    Change: Deducing template arguments from exception specifications.
    Rationale: Facilitate generic handling of throwing and non-throwing functions.
    Effect on original feature: Valid ISO C++20 code may be ill-formed in this revision of C++.

    [Example 1:

       template<bool> struct A { };
       template<bool B> void f(void (*)(A<B>) noexcept(B));
       void g(A<false>) noexcept;
       void h() {
         f(g);    // ill-formed; previously well-formed.
       }
    

    end example]