Namespaces
Variants

Extending the namespace std

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

目录

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(); }
};
  • 特化模板 std::complex 时,除 float double long double 之外的任何类型均属未规范行为。
  • std::atomic 的特化必须具有被删除的拷贝构造函数、被删除的拷贝赋值运算符,以及 constexpr 值构造函数。
  • std::istreambuf_iterator 的特化必须具有平凡的拷贝构造函数、constexpr 默认构造函数,以及平凡的析构函数。
(C++11 起)
(C++17 前)

声明标准库类或类模板的任何成员类模板的完整或部分特化均属于未定义行为。

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

允许向命名空间 std 添加任何标准库函数模板的特化,仅当该声明依赖于至少一个 程序定义类型 ,且该特化满足原始模板的所有要求,除非此类特化被明确禁止。

(C++20 前)

声明任何标准库函数模板的完整特化均属于未定义行为。

(C++20 起)

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

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

变量模板

声明任何标准库变量模板的完整或部分特化均属未定义行为,除非明确允许。

(since C++20)
(since 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);
}

指定的可寻址函数

(since C++20)

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用版本 发布时行为 正确行为
LWG 120 C++98 允许用户为非用户定义类型显式实例化标准库模板 禁止此行为
LWG 232 C++98 若声明依赖于具有外部链接的用户定义名称
(可能引用非用户定义类型),允许用户显式特化标准库模板
仅允许对
用户定义类型进行特化
LWG 422 C++98 允许用户单独特化成员或成员模板
而不特化整个标准库类或类模板
此情况下
行为未定义