On Fri, Sep 2, 2022 at 6:32 AM Peter C++ via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
I think it is doable and desirable. i even was of the impression it would already work,but at least not as of what is in the std.
issues:
- [...] should adoption also work from a FILE*?
- can there be destruction without close?
On 2 Sep 2022, at 11:37, Paul Fee via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
POSIX defines fdopen(), which takes ownership of a low level file descriptor and returns a FILE* with which a user can perform buffered I/O.  There doesn't appear to be a similar feature in C++, though non-standard workarounds exist, such as __gnu_cxx::stdio_filebuf.


Are there issues that would block standardisation of such a facility?  Perhaps it's because fdopen() is part of POSIX rather than ISO C, hence file descriptors themselves may not be universally portable.
Paul: The feature "turn a file descriptor into a FILE" already exists in both C and C++, on POSIX platforms; the POSIX-standard facility is called `fdopen`.
File descriptors are a POSIX-standard thing. File descriptors don't exist, per se, on non-POSIX platforms. So the situation re "turn a file descriptor into a FILE" is already in the best possible state it could ever be in.

However, then there's the next step: "turn a FILE into an ifstream, ofstream, or fstream."  These are things that exist in every standard C++ implementation, because the C++ standard defines both `FILE` (cstdio) and iostreams.  It would be quite reasonable to propose a way to convert a `FILE` into an `{if,of,f}stream`, and/or vice versa.

However, you'll have to figure out what is the right API for this. POSIX uses plain old `int` for all kinds of file descriptors, regardless of readability/writeability. C and C++ use `FILE*` for all kinds of files, regardless of readability/writeability. But the C++ iostreams library uses different types — std::istream for readable files, std::ostream for writeable files. What happens if I do
    FILE *fp = fopen("hello.txt", "r");
    std::ofstream out = std::ofstream(std::from_file, fp);
Does this throw an exception? Is it library UB?  A proposal would have to specify this kind of thing.
Another thing you'll need to figure out — and probably by actually trying to implement this in a real library or two, not just on paper — is whether it's even possible to create a plain `std::ofstream` from a `FILE`, or whether you really need to create a whole new derived class, e.g. `std::ofilestream` (by analogy to `ostringstream`). And then you'll have to decide whether an `ofilestream` IS-AN `ofstream` or merely an `ostream`. See
https://quuxplusone.github.io/blog/2018/11/26/remember-the-ifstream/

Completely off the top of my head, I'd expect the "right" design would be new classes analogous to <sstream>:
    #include <filestream>
    class ifilestream : public istream {};
    class ofilestream : public ostream {};
    class iofilestream : public iostream {};
And by the way, I'm sure you could write these classes today in standard C++, if you really wanted to. Nico Josuttis's "fdstream" implementation is only 200 lines long for the whole thing; replacing the `int fd` and `write` with `FILE *fp` and `fwrite` probably wouldn't be very hard.
http://www.josuttis.com/cppcode/fdstream.html

Peter asks: Can there be destruction without (explicit) close? — Yes, the semantics of `fstream` are that if you destroy an `fstream` without explicitly `.close()`'ing it first, then the destructor will close it for you (and swallow any filesystem errors that might occur).
https://stackoverflow.com/questions/4802494/do-i-need-to-close-a-stdfstream

Paul also wrote:
> Looking at std::format [C++20], it outputs strings.  std::print [C++23], outputs to FILE*.  Does this suggest iostream gets sidelined and FILE* becomes more preferable?

No, at least not any more than it has been sidelined in real code for 20+ years.
std::print has overloads taking `std::ostream&` alongside overloads taking `FILE*`, so you will be able to write either of these:
    std::println(stdout, "hello world!");
    std::println(std::cout, "hello world!");
just as today you can write either of these:
    puts("hello world!");
    std::cout << "hello world!\n";
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2093r14.html#wording

HTH,
Arthur