Live data from Hacker News

Three new utility functions in C++23

mariusbancila.ro

171–180 of 196 posts

Re: Three new utility functions in C++23

#171

Earlier quoted context omitted.

> Technically, this isn't the case in C either: the type defaults to `int`, but the compiler will pick a larger type if necessary, e.g. `enum Z { a = ((long long)INT_MAX) + 1 };` if you read this and alarm bells didn't ring in your head I really invite you to immediately go check any enum you may have defined in your code because this is absolutely false with MSVC in C++ ( https://gcc.godbolt.org/z/6bqW9rE81 ) (and C…

In practice I don't think that the latitude of making enum size depend on the enumeration has ever been used as it would be too easy to break the ABI. IIRC compilers have allowed forward declaring enums as an extension before c++11 which obviously doesn't work if the size depends on the definition.

I don't think that's true. Neither C nor C++ would allow you to invoke a function with an incomplete type, regardless of whether it is a `struct` or an `enum`, so there's no ABI issues with forward declaring them, but you wouldn't be able to define or invoke a function that takes an incomplete type argument by value.

    struct A;
    enum B; // as you pointed out, not allowed by the C++ standard

    // fine to declare, define, and invoke
    void fooA(struct A*);
    void fooB(enum B*);

    // ok to forward declare, but you can't call them
    void barA(struct A);
    void barB(enum B);

Re: Three new utility functions in C++23

#172
post #171

Earlier quoted context omitted.

In practice I don't think that the latitude of making enum size depend on the enumeration has ever been used as it would be too easy to break the ABI. IIRC compilers have allowed forward declaring enums as an extension before c++11 which obviously doesn't work if the size depends on the definition.

I don't think that's true. Neither C nor C++ would allow you to invoke a function with an incomplete type, regardless of whether it is a `struct` or an `enum`, so there's no ABI issues with forward declaring them, but you wouldn't be able to define or invoke a function that takes an incomplete type argument by value. struct A; enum B; // as you pointed out, not allowed by the C++ standard // fine to declare, define,…

Well I misremembered it seems. You can use forward declared enum class or enum : in C++ as per standard:

   enum class A; // defaults to int
   enum B :int;
   enum C;
   fooA(A);
   FooB(B);
   FooC(C);

   fooA((A)0);
   fooB((B)0);
   fooC((C)0); // error
but indeed GCC refuses plain enum. Forward declaring enums in C is an old GCC extension that still deosn't allow to pass them when incomplete;

Enums in GCC do always default to int or unsigned int, unless -fshot-enums is used which is ABI breaking.

Probably I was misremembering this combination of the int ABI and the forward declaring extension.

Re: Three new utility functions in C++23

#173
No thanks, I'm going to keep calling abort (ANSI C, 1989) to indicate "control stops here":

Code after an abort() call is unreachable. (Or after any function attributed noreturn).

GCC and Clang know this, and do things accordingly.

For instance, I've seen GCC emit code which assumes that ptr is not null after ASSERT(ptr != NULL), because the custom ASSERT macro called an __attribute__((noreturn)) function in the null case.

abort() has defined behavior; it terminates the program abnormally, as if by raising the SIGABRT signal.

Your own function attributed __noreturn__ can have whatever behavior you want it to have. The one in the ASSERT macro I alluded to above calculates and prints a backtrace and other useful information.

Re: Three new utility functions in C++23

#174

My first impression is that all three of these are clutter to an already very cluttered language ... 1.) Coming from embedded programming, I can see the utility of `std::unreachable`. But shouldn't this be a compiler directive? Or a standardized #pragma? Can someone more knowledgeable in C++ say whether using functions as markers is a common mechanism in std:: ? 2.)Maybe the example is bad here, as it doesn't even sa…

> But shouldn't this be a compiler directive?

Lisp perspective: anything that can be a function almost certainly should be a function (and not a special operator or macro).

std::unreachable() does not have any arguments; therefore it doesn't need any special argument evaluation semantics that would require a compiler built-in.

The way C and C++ work, compiler directives are keywords and not identifiers. Keywords are not namespaced. Introducing a keyword called "unreachable" is problematic; far more so than a new element in the std namespace.

My only problem with std::unreachable is that I would never use it over std::abort.

Nobody needs a function whose only job is to invoke undefined behavior (from which it is then assumed that it is not reached).

It's a good cold day, so I can almost hear the Rust people laughing in the distance.

Re: Three new utility functions in C++23

#175

Earlier quoted context omitted.

If you have undefined behavior, your program is already broken. No such thing as "more broken"; there's already no theoretical limit to what might happen if it gets triggered.

Undefined behavior is considered worse than crashing, which is typically the alternative when reaching "unreachable" codepaths. Compare these two blocks similar to the article switch (ch) { case 'a': do_a(); return; case 'd': do_d(); return; // ch is guaranteed to be 'a' or 'd' by previous code. default: assert(0); } switch (ch) { case 'a': do_a(); return; case 'd': do_d(); return; default: std::unreachable(); } If t…

I get your point, but assert is usually removed in release builds. Abort would probably be better if you want to crash the program.

Re: Three new utility functions in C++23

#176

My first impression is that all three of these are clutter to an already very cluttered language ... 1.) Coming from embedded programming, I can see the utility of `std::unreachable`. But shouldn't this be a compiler directive? Or a standardized #pragma? Can someone more knowledgeable in C++ say whether using functions as markers is a common mechanism in std:: ? 2.)Maybe the example is bad here, as it doesn't even sa…

> But shouldn't this be a compiler directive? Lisp perspective: anything that can be a function almost certainly should be a function (and not a special operator or macro). std::unreachable() does not have any arguments; therefore it doesn't need any special argument evaluation semantics that would require a compiler built-in. The way C and C++ work, compiler directives are keywords and not identifiers. Keywords are…

To be clear, Rust has this exact same functionality, with an intrinsic as well as a regular function that wraps said intrinsic.

The only difference is that it’s marked unsafe.

https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked....

There is a safe version that is just a wrapper around panic! with a standardized message.

Re: Three new utility functions in C++23

#177
post #146

Earlier quoted context omitted.

What's bizarre about asserts being disabled if you explicitly ask for it?

I'm not asking for the assert to be disabled. I'm asking for debugging features to be disabled. (NDEBUG == "no debug.") The debugging feature of an assert statement is that it performs work to check if the assertion is true and provides diagnostics if not. Disabling the debugging feature of an assert would, in my mind, make it purely an assertion -- an assumption that the compiler can count on (since this is true by…

The sole intent of NDEBUG in the Standard is to suppress assert(). There's a reasonable argument to be made here that it's poorly named (although I suspect that ANSI simply standardized existing practice here, as they did with much of the standard).

Re: Three new utility functions in C++23

#178

Earlier quoted context omitted.

While this is true to some extent, trying to be overly generic and solving for all cases is the root of the analysis-parslysis. I end up solving just the part that's needed for the problem in hand but accepting meaningful compromises and trade offs when faced with this issue.

Premature generalisation is the root of all evil. According to Stepanov generalisation is something you are supposed to discover as you develop a program, not something you do from first principles.

That may be relevant when you're writing a program. When you're writing a _library_, the "discovery" has already happened. But you can't just use the minimum level of generalization useful for your own program(s), you need to consider the conceivable needs of fellow programmers.

Re: Three new utility functions in C++23

#179
post #146

Earlier quoted context omitted.

I'm not asking for the assert to be disabled. I'm asking for debugging features to be disabled. (NDEBUG == "no debug.") The debugging feature of an assert statement is that it performs work to check if the assertion is true and provides diagnostics if not. Disabling the debugging feature of an assert would, in my mind, make it purely an assertion -- an assumption that the compiler can count on (since this is true by…

The sole intent of NDEBUG in the Standard is to suppress assert(). There's a reasonable argument to be made here that it's poorly named (although I suspect that ANSI simply standardized existing practice here, as they did with much of the standard).

Surely you mean ISO and not ANSI? Were such ugly hacks already a part of C89?

Re: Three new utility functions in C++23

#180
post #161

Earlier quoted context omitted.

Well, first, whether swap() is used or not depends on the algorithm; second, the result of the sorting, as opposed to reversal, does not necessary look like the elements were swapped.

> whether swap() is used or not depends on the algorithm I didn't mean the std::swap() function itself, but the swapping of two elements a[i] and a[j]. Is there any sorting algorithm that doesn't rely on swapping two elements (or two parts of the array)? I guess, only if the sort is not being done in-place and the result is stored in a different variable/memory. > does not necessary look like the elements were swappe…

There are in-place algorithms that use shifting rather than swapping (the so called in-place merge sort, for instance).

If you look at the result and at the original, generally you will not find many pairs in which the elements exchanged their positions. It takes special initial arrangements for this to be true for all elements.

Post reply on HN