206 lines
22 KiB
HTML
206 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>扩充命名空间 std</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_extending_std skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">扩充命名空间 <code>std</code></h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<h3><span class="mw-headline" id=".E5.90.91_std_.E6.B7.BB.E5.8A.A0.E5.A3.B0.E6.98.8E">向 <code>std</code> 添加声明</span></h3>
|
|
<p>向 <code>namespace std</code> 或 <code>std</code> 中嵌套的任何命名空间添加声明或定义,除了下面提到的少数例外,都是未定义行为:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <utility></span>
|
|
<span class="kw1">namespace</span> std <span class="br0">{</span>
|
|
<span class="co1">// 向命名空间 std 添加函数:未定义行为</span>
|
|
pair<span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span> operator<span class="sy2">+</span><span class="br0">(</span>pair<span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span> a, pair<span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span> b<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="br0">{</span>a.<span class="me1">first</span><span class="sy2">+</span>b.<span class="me1">first</span>, a.<span class="me1">second</span><span class="sy2">+</span>b.<span class="me1">second</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.B7.BB.E5.8A.A0.E6.A8.A1.E6.9D.BF.E7.89.B9.E5.8C.96">添加模板特化</span></h3>
|
|
<h4><span class="mw-headline" id=".E7.B1.BB.E6.A8.A1.E6.9D.BF">类模板</span></h4>
|
|
<p>对于任何标准库类模板的模板特化,仅当其声明依赖于至少一个程序定义类型,且该特化满足原模板的所有要求时,才允许向命名空间 <code>std</code> 中添加,除非这种特化被禁止。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 获取主 std::hash 模板的声明。不容许我等自己声明它。</span>
|
|
<span class="co1">// 保证 <typeindex> 提供这种声明,包含它比 <functional> 低廉很多。</span>
|
|
|
|
<span class="co2">#include <typeindex> </span>
|
|
|
|
<span class="co1">// 特化 std::hash 使得能以 MyType 为</span>
|
|
<span class="co1">// std::unordered_set 和 std::unordered_map 中的键</span>
|
|
<span class="kw1">namespace</span> std <span class="br0">{</span>
|
|
<span class="kw1">template</span> <span class="sy1"><></span> <span class="kw1">struct</span> hash<span class="sy1"><</span>MyType<span class="sy1">></span> <span class="br0">{</span>
|
|
<a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">const</span> MyType<span class="sy3">&</span> t<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span> <span class="kw1">return</span> t.<span class="me1">hash</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>对 <code>float</code>、<code>double</code>、<code>long double</code> 以外的类型特化 <span class="t-lc"><a href="cpp-numeric-complex.html">std::complex</a></span> 是未指明的。</li>
|
|
</ul>
|
|
<ul>
|
|
<li><span class="t-lc"><a href="cpp-types-numeric_limits.html">std::numeric_limits</a></span> 的特化必须对主模板中所有声明为 <span class="t-rev-inl t-until-cxx11"><span><code>static const</code></span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span><span class="t-rev-inl t-since-cxx11"><span><code>static constexpr</code></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span> 的成员进行定义,而且要使得它们能用作<a href="cpp-language-constant_expression.html">整型常量表达式</a>。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>除了 <span class="t-lc"><a href="cpp-types-common_type.html">std::common_type</a></span> <span class="t-rev-inl t-since-cxx20"><span>与 <span class="t-lc">std::basic_common_reference</span></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>之外,<a href="cpp-header-type_traits.html"><tt><type_traits></tt></a> 中定义的模板均不可对程序定义类型特化。这包含各种<a href="cpp-types.html">类型特征</a>和 <span class="t-lc"><a href="cpp-types-integral_constant.html">std::integral_constant</a></span> 类模板。</li>
|
|
</ul>
|
|
<ul>
|
|
<li>对程序定义类型特化的 <span class="t-lc"><a href="cpp-utility-hash.html">std::hash</a></span> 必须满足<a href="cpp-named_req-Hash.html"><span style="font-style:italic">散列</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(Hash)</span></a> 要求。</li>
|
|
</ul>
|
|
<ul>
|
|
<li><span class="t-lc"><a href="cpp-atomic-atomic.html">std::atomic</a></span> 的特化必须拥有被删除的复制构造函数,被删除的复制赋值运算符,及一个 constexpr 值构造函数。</li>
|
|
</ul>
|
|
<ul>
|
|
<li><span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 及 <span class="t-lc"><a href="cpp-memory-weak_ptr.html">std::weak_ptr</a></span> 的特化必须为<a href="cpp-named_req-CopyConstructible.html"><span style="font-style:italic">可复制构造</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(CopyConstructible)</span></a> 且<a href="cpp-named_req-CopyAssignable.html"><span style="font-style:italic">可复制赋值</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(CopyAssignable)</span></a> 。另外,<span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 的特化必须<a href="cpp-named_req-LessThanComparable.html"><span style="font-style:italic">可小于比较</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LessThanComparable)</span></a> ,而且可转换为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span>。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<ul>
|
|
<li><span class="t-lc"><a href="cpp-iterator-istreambuf_iterator.html">std::istreambuf_iterator</a></span> 的特化必须有平凡复制构造函数、constexpr 默认构造函数,及平凡析构函数。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li>不可特化 <span class="t-lc"><a href="cpp-utility-functional-unary_function.html">std::unary_function</a></span> 与 <span class="t-lc"><a href="cpp-utility-functional-binary_function.html">std::binary_function</a></span>。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>声明标准库类或类模板的任何成员类模板的完全或部分特化是未定义行为。</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E4.B8.8E.E6.A8.A1.E6.9D.BF.E7.9A.84.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0">函数模板与模板的成员函数</span></h4>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p>对于任何标准库函数模板的模板特化,仅当其声明依赖于至少一个程序定义类型,且该特化满足原模板的所有要求时,才允许向命名空间 <code>std</code> 中添加,除非这种特化被禁止。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>声明任何标准库函数模板的完全特化是未定义行为。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
<p>声明标准库类或类模板的任何成员函数模板的完全特化是未定义行为</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
<p>声明标准库类模板的任何成员函数的完全特化是未定义行为</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E5.8F.98.E9.87.8F.E6.A8.A1.E6.9D.BF">变量模板</span></h4>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx14">
|
|
<td>
|
|
<p>声明任何标准库变量模板的完全特化或部分特化是未定义行为,除了显式允许的变量模板。</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-iterator-sized_sentinel_for.html"><tt>std::disable_sized_sentinel_for</tt></a> 、 <a href="cpp-ranges-sized_range.html"><tt>std::ranges::disable_sized_range</tt></a> 、 <a href="cpp-ranges-view.html"><tt>std::ranges::enable_view</tt></a> 与 <a href="cpp-ranges-borrowed_range.html"><tt>std::ranges::enable_borrowed_range</tt></a> 的特化必须可用于常量表达式并拥有 <code>const bool</code> 类型。而且
|
|
<ul>
|
|
<li><code>std::disable_sized_sentinel_for</code> 可对无 cv 限定的非数组对象类型 <code>S</code> 与 <code>I</code> 特化,其中至少一者须为程序定义类型。</li>
|
|
<li><code>std::ranges::disable_sized_range</code> 、 <code>std::ranges::enable_view</code> 与 <code>std::ranges::enable_borrowed_range</code> 可对无 cv 限定的程序定义类型特化。</li>
|
|
</ul>
|
|
</li>
|
|
<li>每个<a href="cpp-numeric-constants.html">数学常数变量模板</a>均可被部分或显式特化,只要该特化依赖程序定义类型。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E6.A8.A1.E6.9D.BF.E7.9A.84.E6.98.BE.E5.BC.8F.E5.AE.9E.E4.BE.8B.E5.8C.96">模板的显式实例化</span></h3>
|
|
<p>对于标准库中定义的<span class="t-rev-inl t-since-cxx20"><span>类</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>模板的显式实例化,仅当其声明依赖于至少一个程序定义类型的名称,且实例化满足标准库对原始模板的要求时,允许进行显示实例化。</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:小示例</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.A8.8B.E5.BA.8F.E5.AE.9A.E4.B9.89.E7.B1.BB.E5.9E.8B">程序定义类型</span></h3>
|
|
<p><i>程序定义特化</i>是既非标准库的一部分亦非实现所定义的显式模板特化或部分特化。</p>
|
|
<p><i>程序定义类型</i>是既非标准库的一部分亦非实现所定义的非闭包<a href="cpp-language-class.html">类类型</a>或<a href="cpp-language-enum.html">枚举类型</a><span class="t-rev-inl t-since-cxx11"><span>,或非实现所提供的 lambda 表达式的<a href="cpp-language-lambda.html">闭包类型</a></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>,或程序定义特化的实例化。</p>
|
|
<h3><span class="mw-headline" id=".E5.85.B6.E4.BB.96.E9.99.90.E5.88.B6">其他限制</span></h3>
|
|
<p>不可将命名空间 <code>std</code> 声明为 <code>inline</code> 命名空间。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<h4><span class="mw-headline" id=".E5.8F.AF.E5.8F.96.E5.9D.80.E5.87.BD.E6.95.B0">可取址函数</span></h4>
|
|
<p>若 C++ 程序显式或隐式形成指向标准库函数或标准库函数模板实例化的指针、引用(对于自由函数和静态成员函数)或成员指针(对于非静态成员函数),则程序行为未指明(可能非良构),除非该函数被指定为<i>可取址函数</i>。</p>
|
|
<p>标准库中仅有的可取址函数是作为函数(或函数模板实例化),接收一个流对象的引用作为其唯一实参的 <a href="cpp-io-manip.html">I/O 操纵符</a>,如 <span class="t-lc"><a href="cpp-io-manip-endl.html">std::endl</a></span>、<span class="t-lc"><a href="cpp-io-manip-boolalpha.html">std::boolalpha</a></span>。</p>
|
|
<p>下列代码在 C++17 中有恰当定义,但从 C++20 起导致未指明行为并且可能无法编译:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <cmath></span>
|
|
<span class="co2">#include <memory></span>
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">auto</span> fptr0 <span class="sy1">=</span> <span class="sy3">&</span><a href="cpp-numeric-special_math-beta.html"><span class="kw1394">std::<span class="me2">betaf</span></span></a><span class="sy4">;</span> <span class="co1">// 通过一元 operator&</span>
|
|
<span class="kw4">auto</span> fptr1 <span class="sy1">=</span> <a href="cpp-memory-addressof.html"><span class="kw757">std::<span class="me2">addressof</span></span></a><span class="br0">(</span><a href="cpp-numeric-special_math-beta.html"><span class="kw1395">std::<span class="me2">betal</span></span></a><span class="br0">)</span> <span class="co1">// 通过 std::addressof</span>
|
|
<span class="kw4">auto</span> fptr2 <span class="sy1">=</span> <a href="cpp-numeric-special_math-riemann_zeta.html"><span class="kw1439">std::<span class="me2">riemann_zetaf</span></span></a><span class="sy4">;</span> <span class="co1">// 通过函数到指针隐式转换</span>
|
|
<span class="kw4">auto</span> <span class="sy3">&</span>fref <span class="sy1">=</span> <a href="cpp-numeric-special_math-riemann_zeta.html"><span class="kw1440">std::<span class="me2">riemann_zetal</span></span></a><span class="sy4">;</span> <span class="co1">// 形成引用</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|