User-defined Literals for std::filesystem::path

Introduction

This paper proposes three sets of user-defined literals for std::filesystem::path(operator "" native, operator "" generic and operator "" path), each of which has the same effect to the constructor call with one particular format, respectively. Therefore those user-defined literals do not only create "path literals," but also act as “named constructors.”

Motivation

C++17 introduces a new filesystem library containing a class std::filesystem::path to represent a file/directory path value. Currently to create a prvalue of std::filesystem::path from a narrow/wide/u16/u32 string literal, users have to explicitly call the constructors, making the code unnecessary verbose. In particular, if a user wants to create a prvalue of std::filesystem::path in specific path format, the user has to specify it by setting the last argument to the constructor call, making the code even more verbose:

One possible workaround is to use auto_format, the default value for the format parameter, instead of explicitly setting it. However, that would cause the program to detect the format at runtime, resulting in a runtime overhead, which is unnecessary for users that do not need auto format detection. Therefore such workaround is a bit against zero-overhead abstraction and “You don’t pay for what you don’t need” principle.

The above dilemmas can be easily solved if we introduce two set of user-defined literals operator "" generic and operator "" native in a new inline namespace std::filesystem::literals, each of which is responsible for creating an std::filesystem::path object of one specific path format respectively. The code above can then be rewritten like this:

Here the user-defined literal works like “named constructor” in other languages such as Vala.

To improve orthogonality, we also add another set of user-defined literals operator "" path being responsible for creating an std::filesystem::path object with path format set to auto_format.

Discussion

UTF-8 string literal issues

The current standard uses a different approach to create a path object from a UTF-8 string literal: std::filesystem::u8path. It would be ideal if std::filesystem::path object could be constructed through a UTF-8 string literal just like the others. But this is not possible because UTF-8 string literals and narrow string literals share the same type; therefore it cannot be distinguished in the declarations of user-defined literals. Furthermore std::filesystem::u8path does not accept a path format argument. From the reasons above we decided not to add anything that directly has something to do with UTF-8 string literals before the Standard Committee get a solution about the type of UTF-8 string literals.

Namespace to put

By far all user-defined literals in the standard library are defined within namespace std::literals, and all the types of the objects those user-defined literals constructs are defined directly in namespace std. This proposal, however, suggests to put std::filesystem::path literals in an inline namespace called std::filesystem::literals, to avoid any potential name conflicts in the future.