扩充命名空间 std

来自cppreference.com
< cpp‎ | language
 
 
C++ 语言
 

std 添加声明

向命名空间 stdstd 中嵌套的任何命名空间添加声明或定义在除了下面提到的少数例外的情况下都是未定义行为。

#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(); }
};
  • floatdoublelong double 以外的类型特化 std::complex 是未指明的。
  • std::atomic 的特化必须拥有被删除的复制构造函数,被删除的复制赋值运算符,和一个 constexpr 值构造函数。
(C++11 起)
  • std::istreambuf_iterator 的特化必须有平凡的复制构造函数,constexpr 默认构造函数,和平凡的析构函数。
(C++17 前)

声明标准库类或类模板的任何成员类模板的完全或部分特化都是未定义行为。

函数模板与模板的成员函数

对于任何标准库函数模板的模板特化,只有在它的声明依赖至少一个程序定义类型,且该特化满足原模板的所有要求时,才能向命名空间 std 中添加,除非这种特化被禁止。

(C++20 前)

声明任何标准库函数模板的完全特化都是未定义行为。

(C++20 起)

声明标准库类或类模板的任何成员函数模板的完全特化都是未定义行为:

声明标准库类模板的任何成员函数的完全特化都是未定义行为:

变量模板

声明任何标准库变量模板的完全特化或部分特化是未定义行为,除了显式允许的变量模板。

(C++14 起)
(C++20 起)

模板的显式实例化

对于标准库中定义的 (C++20 起)模板的显式实例化,只有在它的声明依赖至少一个程序定义类型的名称,且实例化满足标准库对原始模板的要求时,才能进行显示实例化。

程序定义类型

程序定义特化是既不在标准库也不由实现定义的显式模板特化或部分特化。

程序定义类型是既不在标准库也不由实现定义的非闭包类类型枚举类型,或不由实现提供的 lambda 表达式的闭包类型 (C++11 起),或程序定义特化的实例化。

其他限制

不能将命名空间 std 声明为内联命名空间

取址限制

如果 C++ 程序显式或隐式地形成到标准库函数或标准库函数模板实例化的指针、引用(对于自由函数和静态成员函数)或成员指针(对于非静态成员函数),那么程序行为未指明(可能非良构),除非该函数被指定为可取址函数(见下文)。

下列代码的行为未指定,并且可能无法编译:

#include <cmath>
#include <memory>
 
int main()
{
    auto fptr0 = &std::betaf; // 通过一元 operator&
    auto fptr1 = std::addressof(std::betal) // 通过 std::addressof
    auto fptr2 = std::riemann_zetaf; // 通过函数到指针隐式转换
    auto &fref = std::riemann_zetal; // 形成引用
}

指定的可取址函数

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 120 C++98 用户可以以非用户定义类型显式实例化标准库模板 已禁止
LWG 232 C++98 用户可以在声明依赖了具有外部链接的名字的情况下显式
特化标准库模板(即使该名字表示的不是用户定义类型)
仅限用户定义类型
LWG 422 C++98 用户可以在不特化整个标准库类或类模板的情况下单独特化它的成员或成员模板 行为未定义