What does it mean for C++ that assert takes a scalar argument?

161 views
Skip to first unread message

stephan.bergm...@googlemail.com

unread,
Sep 23, 2014, 12:24:00 PM9/23/14
to std-dis...@isocpp.org
The C standard mandates that the assert macro takes an argument of scalar type [7.2.1.1], and defines scalar types to be the collection of arithmetic and pointer types [6.2.5].

The C++ standard delegates matters regarding to assert to the C standard without further ado [assertions].

The C++ standard defines scalar types to be the collection of arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of those [basic.types].  But presumably assert shall be restricted in C++ to the C-notion of scalar types?  At least for scoped enumeration types it would not make sense to allow them as argument types to assert.  But then again, for pointer to member types and std::nullptr_t it probably would?

For non-scalar C++ types that have conversion functions to bool, should it be OK to use them as argument types to assert, or would that be non-portable at best?
  Specifically, the assert.h provided on Mac OS X expands to a use of GCC-specific __builtin_expect, taking a parameter of type long, so that with x of a type that only has an explicit conversion function to bool, assert(x) fails to compile.  My current understanding is that that implementation is indeed allowed to reject that call.

However, it would feel more natural if for C++ assert were defined to take an argument that can be contextually converted to bool.  Has this ever been discussed?

Stephan

Jens Maurer

unread,
Sep 24, 2014, 4:27:13 PM9/24/14
to std-dis...@isocpp.org
On 09/23/2014 06:24 PM, stephan.bergm...@googlemail.com wrote:
> The C standard mandates that the assert macro takes an argument of scalar type [7.2.1.1], and defines scalar types to be the collection of arithmetic and pointer types [6.2.5].
>
> The C++ standard delegates matters regarding to assert to the C standard without further ado [assertions].
>
> The C++ standard defines scalar types to be the collection of arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of those [basic.types]. But presumably assert shall be restricted in C++ to the C-notion of scalar types? At least for scoped enumeration types it would not make sense to allow them as argument types to assert. But then again, for pointer to member types and std::nullptr_t it probably would?
>
> For non-scalar C++ types that have conversion functions to bool, should it be OK to use them as argument types to assert, or would that be non-portable at best?
> Specifically, the assert.h provided on Mac OS X expands to a use of GCC-specific __builtin_expect, taking a parameter of type long, so that with x of a type that only has an explicit conversion function to bool, assert(x) fails to compile. My current understanding is that that implementation is indeed allowed to reject that call.

I sort-of share your pain, but the pitfalls around assert() make me wonder
why I should invest effort into making it more C++-friendly.

(In particular, it's a macro, so side effects in its argument will vanish
when compiling with -DNDEBUG.)

Some dead horses are best left alone.

> However, it would feel more natural if for C++ assert were defined to take an argument that can be contextually converted to bool. Has this ever been discussed?

Not to my knowledge.

Jens

stephan.bergm...@googlemail.com

unread,
Sep 25, 2014, 11:16:03 AM9/25/14
to std-dis...@isocpp.org
On Wednesday, September 24, 2014 10:27:13 PM UTC+2, Jens Maurer wrote:
I sort-of share your pain, but the pitfalls around assert() make me wonder
why I should invest effort into making it more C++-friendly.

(In particular, it's a macro, so side effects in its argument will vanish
when compiling with -DNDEBUG.)

Some dead horses are best left alone.

But is it really dead, or does it have to be?  It serves an important purpose, and I see no alternative facility in Standard C++ to replace it.  And it probably makes no sense if every C++ project rolls its own re-invention of it.

That arguments are not evaluated in the NDEBUG case (which necessitates it being a macro) is probably a double-sided sword.  While it can probably cause hard-to-spot bugs, it can also be useful to easily confine evaluation of expensive checking code to cases where that checking is actually done, without having to sprinkle the code with #findef NDEBUGs.  (Though being able to restricting the argument to be side-effect--free would certainly be nice.)

The related nuisance of bogus "unused variable" etc. warnings because the argument is invisible to the compiler in the NDEBUG case could be solved by dropping the ((void*)0) requirement as discussed in the recent "DR: assert macro is overconstrained" thread.

Or am I missing something?

Olaf van der Spek

unread,
Sep 25, 2014, 5:14:58 PM9/25/14
to std-dis...@isocpp.org
Op woensdag 24 september 2014 22:27:13 UTC+2 schreef Jens Maurer:
On 09/23/2014 06:24 PM, stephan.bergm...@googlemail.com wrote:
> The C standard mandates that the assert macro takes an argument of scalar type [7.2.1.1], and defines scalar types to be the collection of arithmetic and pointer types [6.2.5].
>
> The C++ standard delegates matters regarding to assert to the C standard without further ado [assertions].
>
> The C++ standard defines scalar types to be the collection of arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of those [basic.types].  But presumably assert shall be restricted in C++ to the C-notion of scalar types?  At least for scoped enumeration types it would not make sense to allow them as argument types to assert.  But then again, for pointer to member types and std::nullptr_t it probably would?
>
> For non-scalar C++ types that have conversion functions to bool, should it be OK to use them as argument types to assert, or would that be non-portable at best?
>   Specifically, the assert.h provided on Mac OS X expands to a use of GCC-specific __builtin_expect, taking a parameter of type long, so that with x of a type that only has an explicit conversion function to bool, assert(x) fails to compile.  My current understanding is that that implementation is indeed allowed to reject that call.

I sort-of share your pain, but the pitfalls around assert() make me wonder
why I should invest effort into making it more C++-friendly.

What pitfalls?

 (In particular, it's a macro, so side effects in its argument will vanish 
when compiling with -DNDEBUG.)


That's a feature, isn't it?
If you want side effects to remain, you're looking for something like BOOST_VERIFY which unfortunately has no equivalent in standard C++. 

stephan.bergm...@googlemail.com

unread,
Oct 17, 2014, 9:23:56 AM10/17/14
to std-dis...@isocpp.org, stephan.bergm...@googlemail.com
On Tuesday, September 23, 2014 6:24:00 PM UTC+2, stephan.bergm...@googlemail.com wrote:
However, it would feel more natural if for C++ assert were defined to take an argument that can be contextually converted to bool.  Has this ever been discussed?

Ah, I see there is N4154: "Operator assert" now.

David Krauss

unread,
Oct 17, 2014, 6:06:46 PM10/17/14
to std-dis...@isocpp.org
Yes, I didn’t actually reply to this thread, but it helped inspire the paper.

Now there’s also N4135, which notes that it removed references to the preprocessor relative to its previous revision, but it remains a bit more ambiguous about the processing of disabled assertions. It might be a good idea to unify the two proposals.
Reply all
Reply to author
Forward
0 new messages