2676. Provide filesystem::path overloads for File-based streams

Section: 30.9 [file.streams] Status: C++17 Submitter: Beman Dawes Opened: 2016-03-16 Last modified: 2017-07-30

Priority: 2

View all other issues in [file.streams].

View all issues with C++17 status.

Discussion:

The constructor and open functions for File-based streams in 27.9 [file.streams] currently provide overloads for const char* and const string& arguments that specify the path for the file to be opened. With the addition of the File System TS to the standard library, these constructors and open functions need to be overloaded for const filesystem::path& so that file-based streams can take advantage of class filesystem::path features such as support for strings of character types wchar_t, char16_t, and char32_t.

The const filesystem::path& p overload for these functions is like the existing const string& overload; it simply calls the overload of the same function that takes a C-style string.

For operating systems like POSIX that traffic in char strings for filenames, nothing more is required. For operating systems like Windows that traffic in wchar_t strings for filenames, an additional C-style string overload is required. The overload's character type needs to be specified as std::filesystem::path::value_type to also support possible future operating systems that traffic in char16_t or char32_t characters.

Not recommended:

Given the proposed constructor and open signatures taking const filesystem::path&, it would in theory be possible to remove some of the other signatures. This is not proposed because it would break ABI's, break user code depending on user-defined automatic conversions to the existing argument types, and invalidate existing documentation, books, and tutorials.

Implementation experience:

The Boost Filesystem library has provided header <boost/filesystem/fstream.hpp> implementing the proposed resolution for over a decade.

The Microsoft/Dinkumware implementation of standard library header <fstream> has provided the const wchar_t* overloads for many years.

[2016-08-03 Chicago]

Fri PM: Move to Review

Proposed resolution:

At the end of 27.9.1 File streams [fstreams] add a paragraph:

In this subclause, member functions taking arguments of const std::filesystem::path::value_type* shall only be provided on systems where std::filesystem::path::value_type ([fs.class.path]) is not char. [Note: These functions enable class path support for systems with a wide native path character type, such as wchar_t. — end note]

Change 27.9.1.1 Class template basic_filebuf [filebuf] as indicated:

basic_filebuf<charT,traits>* open(const char* s,
    ios_base::openmode mode);
basic_filebuf<charT,traits>* open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode);  // wide systems only; see [fstreams] 
basic_filebuf<charT,traits>* open(const string& s,
   ios_base::openmode mode);
basic_filebuf<charT,traits>* open(const filesystem::path& p,
   ios_base::openmode mode);

Change 27.9.1.4 Member functions [filebuf.members] as indicated:

basic_filebuf<charT,traits>* open(const char* s,
   ios_base::openmode mode);
basic_filebuf<charT,traits>* open(const std::filesystem::path::value_type* s,
   ios_base::openmode mode);  // wide systems only; see [fstreams]

To 27.9.1.4 Member functions [filebuf.members] add:

basic_filebuf<charT,traits>* open(const filesystem::path& p,
   ios_base::openmode mode);

Returns: open(p.c_str(), mode);

Change 27.9.1.6 Class template basic_ifstream [ifstream] as indicated:

explicit basic_ifstream(const char* s,
    ios_base::openmode mode = ios_base::in);
explicit basic_ifstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in);  // wide systems only; see [fstreams]
explicit basic_ifstream(const string& s,
    ios_base::openmode mode = ios_base::in);
explicit basic_ifstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in);
...
void open(const char* s,
    ios_base::openmode mode = ios_base::in);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in);  // wide systems only; see [fstreams]
void open(const string& s,
    ios_base::openmode mode = ios_base::in);
void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in);

Change 27.9.1.7 basic_ifstream constructors [ifstream.cons] as indicated:

explicit basic_ifstream(const char* s,
    ios_base::openmode mode = ios_base::in);
explicit basic_ifstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in);  // wide systems only; see [fstreams]

To 27.9.1.7 basic_ifstream constructors [ifstream.cons] add:

explicit basic_ifstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in);

Effects: the same as basic_ifstream(p.c_str(), mode).

Change 27.9.1.9 Member functions [ifstream.members] as indicated:

void open(const char* s,
    ios_base::openmode mode = ios_base::in);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in);  // wide systems only; see [fstreams]

To 27.9.1.9 Member functions [ifstream.members] add:

void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in);

Effects: calls open(p.c_str(), mode).

Change 27.9.1.10 Class template basic_ofstream [ofstream] as indicated:

explicit basic_ofstream(const char* s,
    ios_base::openmode mode = ios_base::out);
explicit basic_ofstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::out);  // wide systems only; see [fstreams]
explicit basic_ofstream(const string& s,
    ios_base::openmode mode = ios_base::out);
explicit basic_ofstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::out);
...
void open(const char* s,
    ios_base::openmode mode = ios_base::out);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::out);  // wide systems only; see [fstreams]
void open(const string& s,
    ios_base::openmode mode = ios_base::out);
void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::out);

Change 27.9.1.11 basic_ofstream constructors [ofstream.cons] as indicated:

explicit basic_ofstream(const char* s,
    ios_base::openmode mode = ios_base::out);
explicit basic_ofstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::out);  // wide systems only; see [fstreams]

To 27.9.1.11 basic_ofstream constructors [ofstream.cons] add:

explicit basic_ofstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::out);

Effects: the same as basic_ofstream(p.c_str(), mode).

Change 27.9.1.13 Member functions [ofstream.members] as indicated:

void open(const char* s,
    ios_base::openmode mode = ios_base::out);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::out);  // wide systems only; see [fstreams]

To 27.9.1.13 Member functions [ofstream.members] add:

void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::out);

Effects: calls open(p.c_str(), mode).

Change 27.9.1.14 Class template basic_fstream [fstream] as indicated:

explicit basic_fstream(const char* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
explicit basic_fstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);  // wide systems only; see [fstreams]
explicit basic_fstream(const string& s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
explicit basic_fstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in|ios_base::out);
...
void open(const char* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);  // wide systems only; see [fstreams]
void open(const string& s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in|ios_base::out);

Change 27.9.1.15 basic_fstream constructors [fstream.cons] as indicated:

explicit basic_fstream(const char* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
explicit basic_fstream(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);  // wide systems only; see [fstreams]

To 27.9.1.15 basic_fstream constructors [fstream.cons] add:

explicit basic_fstream(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in|ios_base::out);

Effects: the same as basic_fstream(p.c_str(), mode).

Change 27.9.1.17 Member functions [fstream.members] as indicated:

void open(const char* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);
void open(const std::filesystem::path::value_type* s,
    ios_base::openmode mode = ios_base::in|ios_base::out);  // wide systems only; see [fstreams]

To 27.9.1.17 Member functions [fstream.members] add:

void open(const filesystem::path& p,
    ios_base::openmode mode = ios_base::in|ios_base::out);

Effects: calls open(p.c_str(), mode).