扩充命名空间 std
来自cppreference.com
向 std
添加声明
向命名空间 std
或 std
中嵌套的任何命名空间添加声明或定义,除了下面提到的少数例外的情况下都是未定义行为。
#include <utility> namespace std { // 向命名空间 std 添加函数:未定义行为 pair<int, int> operator+(pair<int, int> a, pair<int, int> b) { return {a.first + b.first, a.second + b.second}; } }
添加模板特化
类模板
对于任何标准库类模板的模板特化,只有在它的声明依赖至少一个由程序定义的类型,且该特化满足原模板的所有要求时,才能向命名空间 std
中添加,除非这种特化被禁止。
// 获取主 std::hash 模板的声明。不能自己声明它。 // 保证 <typeindex> 提供这种声明,包含它比 <functional> 低廉很多。 #include <typeindex> // 特化 std::hash 使得 MyType 可以成为 // std::unordered_set 和 std::unordered_map 中的键。 // 直接展开命名空间 std 可能会引发未定义行为,而且特化类模板也不需要这样做。 template <> struct std::hash<MyType> { std::size_t operator()(const MyType& t) const { return t.hash(); } };
- 对 float、double、long double 以外的类型特化 std::complex 是未指明的。
- std::numeric_limits 的特化必须对主模板中所有声明为 static const (C++11 前)static constexpr (C++11 起) 的成员进行定义,而且要使得它们能用作整数常量表达式。
|
(C++11 起) |
(C++17 前) |
声明标准库类或类模板的任何成员类模板的完全或部分特化都是未定义行为。
本节未完成 原因:小示例 |
函数模板与模板的成员函数
对于任何标准库函数模板的模板特化,只有在它的声明依赖至少一个由程序定义的类型,且该特化满足原模板的所有要求时,才能向命名空间 |
(C++20 前) |
声明任何标准库函数模板的完全特化都是未定义行为。 |
(C++20 起) |
本节未完成 原因:小示例 |
声明标准库类模板的任何成员函数的完全特化都是未定义行为:
本节未完成 原因:小示例 |
声明标准库类或类模板的任何成员函数模板的完全特化都是未定义行为:
本节未完成 原因:小示例 |
变量模板
声明任何标准库变量模板的完全特化或部分特化,除非明确允许,否则都是未定义行为。
|
(C++14 起) |
模板的显式实例化
对于标准库中定义的类 (C++20 起)模板的显式实例化,只有在它的声明依赖至少一个由程序定义的类型的名称,且实例化满足标准库对原始模板的要求时,才能进行显示实例化。
本节未完成 原因:小示例 |
其他限制
不能将命名空间 std
声明为内联命名空间。
取址限制如果 C++ 程序显式或隐式地尝试形成到标准库函数或标准库函数模板实例化的指针、引用(对于自由函数和静态成员函数)或成员指针(对于非静态成员函数),那么程序行为未指明(可能非良构),除非该函数被指定为可取址函数(见下文)。 下列代码在 C++17 中良定义,但从 C++20 起将导致未指定的行为,并且可能无法编译: #include <cmath> #include <memory> int main() { // 通过一元 operator& auto fptr0 = &static_cast<float(&)(float, float)>(std::betaf); // 通过 std::addressof auto fptr1 = std::addressof(static_cast<float(&)(float, float)>(std::betaf)); // 通过函数到指针隐式转换 auto fptr2 = static_cast<float(&)(float)>(std::riemann_zetaf); // 形成引用 auto& fref = static_cast<float(&)(float)>(std::riemann_zetaf); } 指定的可取址函数
|
(C++20 起) |
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
LWG 120 | C++98 | 用户可以以非用户定义类型显式实例化标准库模板 | 已禁止 |
LWG 232 | C++98 | 用户可以在声明依赖了具有外部链接的名字的情况下显式 特化标准库模板(即使该名字表示的不是用户定义类型) |
仅限用户定义类型 |
LWG 422 | C++98 | 用户可以在不特化整个标准库类或类模板的情况下单独特化它的成员或成员模板 | 行为未定义 |