C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Error messages associated with "requires"

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Fri, 22 Sep 2023 09:29:17 +0200
Hi Chris, please compare to   P1267R0: Custom Constraint Diagnostics (2018, by Hana Dusíková and Bryce Adelstein Lelbach, inactive)     https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1267r0.pdf P2429R0: Concepts Error Messages for Humans (2022, by Sy Brand, active)     https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2429r0.pdf   and (generally related) P2573R0: = delete("should have a reason"); (2022, by Yihe Li, active)     https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2573r0.html   Best, Sebastian   -----Ursprüngliche Nachricht----- Von:Chris Gary via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Do 21.09.2023 23:38 Betreff:[std-proposals] Error messages associated with "requires" An:std-proposals_at_[hidden]; CC:Chris Gary <cgary512_at_[hidden]>; Like static_assert, except associated with the evaluation of a specific constraint. Errors generated by the following: `template< typename NoiseMakerT > requires( is_loud_v< NoiseMakerT > && is_annoying_v< NoiseMakerT > ) void OnlyIfLoudAndAnnoying( const NoiseMakerT &N ) { // etc.. }` are immediately opaque when encountered in a diagnostic. Say, putting an "else" with a string literal after a "requires" could allow authors to spell out errors more precisely. `template< typename NoiseMakerT > requires( is_loud_v< NoiseMakerT > && is_annoying_v< NoiseMakerT > ) else ( "The argument type is neither loud or annoying." ) void OnlyIfLoudAndAnnoying( const NoiseMakerT &N ) { // etc.. }` Splitting it up can help to clarify where the situation is more complicated: `template< typename NoiseMakerT > requires( is_loud_v< NoiseMakerT > ) ) else ( "The argument type is not loud." ) requires( is_annoying_v< NoiseMakerT > ) else ( "The argument type is not annoying." ) void OnlyIfLoudAndAnnoying( const NoiseMakerT &N ) { // etc.. }` With concepts: ` template< typename NoiseMakerT > concept LoudAndAnnoying = requires { is_loud_v<NoiseMakerT> && is_annoying_v<NoiseMakerT> } else { "The type is not loud and annoying."; }; template< LoudAndAnnoying NoiseMakerT > else ( "The argument type is neither loud or annoying." ) void OnlyIfLoudAndAnnoying( const NoiseMakerT &noisy ) { // ... }` So, if violated: `class NotLoudOrAnnoying { // ... }; void Fn() {   NotLoudOrAnnoying oops{};   OnlyIfLoudAndAnnoying( oops ); }` This would print something like: "... error: The argument type is neither loud or annoying ..." "... error: The type is not loud and annoying ..." Instead of "a constraint was violated" or something else non-specific (read: eats time diagnosing the meaning of a diagnostic). When printing out errors, the compiler would start from the deepest level of the call stack upwards. An option could be specified to limit error reports to only the first diagnostic. This can also nest into silly things, but it looks to be unambiguous: `template< typename NoiseMakerT > requires(   requires   { is_loud_v< NoiseMakerT > && is_annoying_v< NoiseMakerT > }   else   { "The argument type is neither loud or annoying." } ) void OnlyIfLoudAndAnnoying( const NoiseMakerT &N ) { // etc.. }` -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals  

Received on 2023-09-22 07:29:19