为什么 std::literals 运算符在包含其对应的标头时不会自动导出?

问题描述

std::literals 命名空间中有一些文字运算符及其相应的标头,例如 operator""soperator""sv 等。

我想知道为什么这些运算符在包含相应的标头时不会自动导出,因为它们不会相互冲突,也不会与必须以下划线开头的用户定义文字运算符发生冲突,并且通常像我这样的用户在包含标头时想要使用它们。

如果 using std::string_literals::operator""s; 已经在 <string> 标头以及其他库中,那就太好了:

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

我看不出有什么危害。为什么委员会不喜欢这个?它有什么问题还是这是一种不好的做法?

解决方法

在 C++ 中,using 声明无法被撤销。一旦它在那里,跟在它后面的每一段代码(在它的范围内)都会有它的名称查找规则受该指令影响。因此,全局 using 语句有些危险。在 header 中更危险,因为这会固有地影响包含该标头的每个文件的行为(包括在该标头之后 包含的任何标头)。

因此,C++ 头文件不会将名称放到全局命名空间(C 标准库名称和无法命名的宏除外)。但是,只有在可以在没有命名空间范围的情况下访问 UDL 时,才能使用它们。因此,公开 UDL 的标准习惯用法是坚持,如果您想在某些本地代码中使用文字,正确的习惯用法是自己编写 using 声明。并且您希望在具有 using 范围(如函数定义)的地方使用它们,不是全局或在 namespace 范围内。

在使用 C++20 模块的代码库中,处理这些事情要容易得多,因为如果您明确选择从该模块导出模块,导入模块只会泄漏 using 指令。因此,在模块中全局声明这样的指令不一定会破坏包含该模块的任何代码。