The specification for the assert(scalar expression) macro contains the following in its description:
It turns out that the parenthetical notes "which shall have a scalar type" and "compares equal to 0" are problematic for C++ as discussed in WG21 Library Working Group (LWG) issue 3011.
In C++, user-defined class types may be defined to act almost exactly like scalar types, or like other basic (or in C++ terminology, fundamental) types. By providing implicit conversion operators to the latter types they can be used almost entirely interchangeably. For example, objects of type Nifty defined below can be used in nearly all contexts where type bool is expected. In addition, the objects can be compared for equality to char*.
struct Nifty { operator bool () const; bool operator== (const char*) const; };
An object of type Nifty can be used for example like this:
extern Nifty x; if (x) // converted to bool by Nifty::operator bool() puts ("x is true"); else puts ("x is false");
or like this
if (x == "123") // compared to "123" via Nifty::operator==(const char*) puts ("x equals 123"); else puts ("s does not equal 123");
With this as background, it should be clear that users of type Nifty would naturally expect to be able to use objects of the type in other similar contexts such as the assert macro.
However, because assert is specified to have the described effect when its argument "compares equal to 0", invoking it on a Nifty object would result not in a call to Nifty::operator bool() as its author no doubt intended and its users expect, but rather Nifty::operator==(const char*). Needless to say, it is surprising and thus error-prone for C++ programmers accustomed to C++ rules to have to keep in mind that such an essential facility of the language as the assert macro doesn't play by the same rules. Fedora Linux bug 1482990 provides evidence of this impact.
It might seem that this is a C++ problem, not one for the C standard or its implementation to try to solve. However, similar to POSIX, the C++ standard incorporates the library portion of the C standard largely without change. Likewise, virtually all C++ standard library implementations incorporate the underlying C standard library by reference, often with no ability to make changes or customizations to it. So to solve the problem for C++ the only realistic solution is to compel C standard library implementers to make a change by adjusting the C specification.
In the interest of interoperability between C and C++ we propose to change the specification of assert as follows. In the Synopsis paragraph of §7.2.1.1 The assert macro make the following changes:
#include <assert.h> void assert(scalarexpression);
In paragraph 2 of the same §7.2.1.1 make the following changes:
Finally, change the following bullet from §J.2 Undefined behavior as indicated:
Besides addressing the C/C++ interoperability problem the proposed removal of the reference to "scalar type" in the synopsis and in the first parenthetical note permits the use of arrays and atomic types as assert arguments. A strict reading of the text suggests that objects of those types are not valid arguments in C, but arrays are valid arguments in C++. We believe that allowing them is an improvement since using such arguments is not uncommon in practice, and we are not aware of any reason to preclude them.
We note that objects of atomic types don't appear to be valid operands to the ternary operator. That seems like a defect in the standard.