C++ Logo

std-proposals

Advanced search

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

From: Chris Gary <cgary512_at_[hidden]>
Date: Thu, 21 Sep 2023 15:38:19 -0600
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..
}`

Received on 2023-09-21 21:38:31