命名空间
变体
操作

扩展命名空间 std

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

目录

[编辑] std 添加声明

向命名空间 stdstd 内嵌套的任何命名空间添加声明或定义是未定义行为,但以下列出的几种情况除外。

#include <utility>
 
namespace std
{
    // a function definition added to namespace std: undefined behavior
    pair<int, int> operator+(pair<int, int> a, pair<int, int> b)
    {
        return {a.first + b.first, a.second + b.second};
    }
}

[编辑] 添加模板特化

[编辑] 类模板

只允许在以下情况下向命名空间 std 添加任何标准库类模板的模板特化:声明至少依赖于一个程序定义类型,并且特化满足原始模板的所有要求,除非禁止此类特化。

// Get the declaration of the primary std::hash template.
// We are not permitted to declare it ourselves.
// <typeindex> is guaranteed to provide such a declaration, 
// and is much cheaper to include than <functional>.
 
#include <typeindex> 
 
// Specialize std::hash so that MyType can be used as a key in 
// std::unordered_set and std::unordered_map.  Opening namespace
// std can accidentally introduce undefined behavior, and is not
// necessary for specializing class templates.
template<>
struct std::hash<MyType>
{
    std::size_t operator()(const MyType& t) const { return t.hash(); }
};
  • std::complex 模板特化除 floatdoublelong double 以外的任何类型是未指定的。
  • std::hash 对程序定义类型的特化必须满足 Hash 的要求。
  • std::atomic 的特化必须具有已删除的复制构造函数、已删除的复制赋值运算符和 constexpr 值构造函数。
  • std::istreambuf_iterator 的特化必须具有平凡的复制构造函数、constexpr 默认构造函数和平凡的析构函数。
(自 C++11 起)
(直到 C++17)

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

[编辑] 函数模板和模板的成员函数

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

(直到 C++20)

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

(自 C++20 起)

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

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

[编辑] 变量模板

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

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

[编辑] 模板的显式实例化

只允许在以下情况下显式实例化标准库中定义的(自 C++20 起)模板:声明至少依赖于一个程序定义类型的名称,并且实例化满足原始模板的标准库要求。

[编辑] 其他限制

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

寻址限制

如果 C++ 程序显式或隐式地尝试形成指向标准库函数或标准库函数模板实例化的指针、引用(对于自由函数和静态成员函数)或指向成员的指针(对于非静态成员函数),则其行为是未指定的(可能是格式错误的),除非它被指定为_可寻址函数_(见下文)。

以下代码在 C++17 中是定义良好的,但会导致未指定的行为,并且自 C++20 起可能无法编译

#include <cmath>
#include <memory>
 
int main()
{
    // by unary operator&
    auto fptr0 = &static_cast<float(&)(float, float)>(std::betaf);
 
    // by std::addressof
    auto fptr1 = std::addressof(static_cast<float(&)(float, float)>(std::betaf));
 
    // by function-to-pointer implicit conversion
    auto fptr2 = static_cast<float(&)(float)>(std::riemann_zetaf);
 
    // forming a reference
    auto& fref = static_cast<float(&)(float)>(std::riemann_zetaf);
}

指定的可寻址函数

(自 C++20 起)

[编辑] 缺陷报告

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

缺陷报告 应用于 已发布的行为 正确行为
LWG 120 C++98 用户可以显式实例化非用户定义类型的标准
库模板
禁止
LWG 232 C++98 如果声明依赖于外部链接的用户定义名称(可以引用非用户定义类型),则用户可以显式特化标准库模板
如果声明依赖于外部链接的用户定义名称(可以引用非用户定义类型)
仅允许用于
用户定义类型
LWG 422 C++98 用户可以专门化单个成员或成员模板
而无需专门化整个标准库类或类模板
在这种情况下,行为是
未定义的