First of all, thank you for the response.

You said that you have a function that previously was creating a temporary file on disk (and could generate eaccess) but now it creates it in memory (and can generate enosys instead).
Correct me if I am wrong, but, from what I can gather, you do not want to have a function creating a temp file on disk, nor in memory.
What you want is a facility
* for creating a temporary file somewhere (for example, using a hard-coded logic: first try in memory, if it fails - on disk, or there might be a hint-parameter as to where create it)
* that could report an error (for example in the form of expected<fd, TError>).

The latter is the most interesting part. As I described in my post, I would go for "nested error structure with increasing degree of details":
1st level: I would hazard a guess, for majority of callees "failed/succeeded" is enough - we have expected<> for this.
2nd level, by looking in the man page of the open() syscall, there is a couple of broad groups of errors: AccessFailed, BadArguments, maybe something else - this information might be necessary for a finer-grained handling.
3rd level: precise, primarily debug-only, OS-specific errno code:
struct TError {
   enum TStatus { BadArg, AccessFailed, ... }
   TStatus Status;
   std:::string Args; // used when Status == BadArg
   int SysErrno;
As I wrote in my post, you can enhance this approach however you want, for example place "sub-errors" in a variant<>.

So, with this approach callees have the freedom to choose the level of details they want to know about.
And everything is checked by a compiler: consider the situation when a callee had a switch over TStatus, and then somebody adds a new element in the enum - you will receive a warning from compiler (given you build it together) about not handled case in the switch. This warning is perfectly fine, because, by having the switch, callee "said" that it is interested at this level of details, but somebody changed it - with all likelihood it is better to look at the switch closer.

On Tue, 6 Aug 2019, 06:16 Thiago Macieira via Std-Discussion, <> wrote:
On Monday, 5 August 2019 01:45:13 PDT Dmitry via Std-Discussion wrote:
> I wrote a post -
> y_deprecated/ in the hope to get answers to at least 3 questions at the top
> because the are very practical and I have to deal with them every day.
> I would be grateful to here what you think.

Disclaimer: I don't use exceptions in my code, my libraries never throw, I
never test exception-safety.

But I think you've fallen into the fallacy of focusing on the mechanism
instead of the objective. The exception is the means to transport an error
condition in a type-safe manner and unwind the stack. The same can be
accomplished with error conditions and returns and in fact does happen: I can
make your situations more concrete based on what I did at work today: I had a
function f() that opened a temporary file and returned a file descriptor, but
instead of opening a real file, now it opens a Linux memfd. That means EACCESS
can no longer happen. At the same time, we can get an ENOSYS if you're running
on Linux less than 3.17.

How does the caller's code get updated to handle the new condition and stop
handling the now never-impossible one?

Thiago Macieira - thiago (AT) - thiago (AT)
   Software Architect - Intel System Software Products

Std-Discussion mailing list