c++c++14c++17string-literalsuser-defined-literals

Why does std::literals operators not automatically export when include their correspond header?


There are some literal operators in the std::literals namespace with their corresponding header such as operator""s, operator""sv etc.

I wonder why those operators are not automatically export when including the corresponding header since they cannot conflict with each other or user-defined literals operators which must begin with the underscore and usually users like me want to use them when including the header.

It would be nice that the using std::string_literals::operator""s; already in the <string> header as well as other libraries:

#include <string> // automatically export the literal operators
#include <chrono> // automatically export the literal operators
int main() {
  auto str = "hello world"s;
  auto sec = 10s;
}

I can't see any harm with it. Why does Committee not like this? Is there some issue with it or this is a bad practice?


Solution

  • In C++, a using declaration cannot be undone. Once it's there, every piece of code that follows it (within its scope) will have its name lookup rules affected by that directive. A global using statement is therefore somewhat dangerous. It is even more dangerous in a header, as this will inherently affect the behavior of every file that includes that header (including any headers that get included after that header).

    As such, C++ headers do not drop names to the global namespace (except for C standard library names and macros which cannot be namespaced). But UDLs can only be used if they can be accessed without namespace scopes. Therefore, the standard idiom for exposing UDLs is to stick if you want to use literals in some piece of local code, the correct idiom to use is to write the using declaration yourself. And you want these in places that have using scopes like function definitions, not globally or within a namespace scope.

    In a codebase that uses C++20 modules, it's much easier to deal with these things, as importing a module will only leak a using directive if you explicitly chose to export it from that module. So globally declaring such a directive in a module won't necessarily corrupt any code that includes that module.