397 lines
33 KiB
HTML
397 lines
33 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>constexpr 说明符(C++11 起)</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_constexpr skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">constexpr 说明符<span class="t-mark-rev t-since-cxx11">(C++11 起)</span></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">
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><code><b>constexpr</b></code> - 指定变量或函数的值可以在<a href="cpp-language-constant_expression.html">常量表达式</a>中出现</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p><code>constexpr</code> 说明符声明编译时可以对函数或变量求值值。这些变量和函数(给定了合适的函数实参的情况下)即可用于需要编译期<a href="cpp-language-constant_expression.html">常量表达式</a>的地方。</p>
|
|
<p>声明对象<span class="t-rev-inl t-until-cxx14"><span>或非静态成员函数</span> <span><span class="t-mark-rev t-until-cxx14">(C++14 前)</span></span></span>时使用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 说明符则同时蕴含 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span></span></span>。声明函数<span class="t-rev-inl t-since-cxx17"><span>或<a href="cpp-language-static.html">静态</a>成员变量</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>时使用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 说明符则同时蕴含 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">inline</span></span></span>。如果一个函数或函数模板的某个声明拥有 <code>constexpr</code> 说明符,则其所有声明都必须含有该说明符。</p>
|
|
<p><b><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 变量</b>必须满足下列要求:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它的类型必须是<a href="cpp-named_req-LiteralType.html"><span style="font-style:italic">字面类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LiteralType)</span></a> 。</li>
|
|
<li>它必须被立即初始化。</li>
|
|
<li>它的初始化包括所有隐式转换、构造函数调用等的<a href="cpp-language-eval_order.html">全表达式</a>必须是<a href="cpp-language-constant_expression.html">常量表达式</a></li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p><span id=".E5.B8.B8.E9.87.8F.E6.9E.90.E6.9E.84"></span></p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它必须拥有常量析构,即:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它不是类类型亦或其(可能多维的)数组,或</li>
|
|
<li>它是类类型或其(可能多维的)数组,且该类类型拥有 constexpr 析构函数;对于作用仅为销毁该对象的虚设表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> ,如果该对象与其非 mutable 子对象(但非其 mutable 子对象)的生存期始于 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 内,那么 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 是核心常量表达式。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 变量非<a href="cpp-language-tu_local.html">翻译单元局部</a>,那么它不应被初始化为指向或指代可用于常量表达式的翻译单元局部实体,或拥有指向或指代这种实体的(可能递归的)子对象。这种初始化在<a href="cpp-language-modules.html">模块接口单元</a>(在其私有模块片段外,如果存在)或模块划分中被禁止,并在任何其他语境中被弃用。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><b><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 函数</b>必须满足下列要求:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它必须非<a href="cpp-language-virtual.html">虚</a></li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它必须不是<a href="cpp-language-coroutines.html">协程</a></li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它的返回类型(如果存在)必须是<a href="cpp-named_req-LiteralType.html"><span style="font-style:italic">字面类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LiteralType)</span></a></li>
|
|
<li>它的每个参数都必须是<a href="cpp-named_req-LiteralType.html"><span style="font-style:italic">字面类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LiteralType)</span></a></li>
|
|
<li>对于构造函数<span class="t-rev-inl t-since-cxx20"><span>与析构函数</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>,该类必须无虚基类</li>
|
|
<li>至少存在一组实参值,使得函数的一个调用为<a href="cpp-language-constant_expression.html#.E6.A0.B8.E5.BF.83.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">核心常量表达式</a>的被求值的子表达式<span class="t-rev-inl t-since-cxx14"><span>(对于构造函数为足以用于<a href="cpp-language-constant_initialization.html">常量初始化器</a>)</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>。不要求诊断是否违反这点。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>它的函数体必须不是<a href="cpp-language-function-try-block.html">函数 try 块</a></li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx14">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>函数体必须被弃置或预置,或只含有下列内容:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><a href="cpp-language-statements.html#.E8.A1.A8.E8.BE.BE.E5.BC.8F.E8.AF.AD.E5.8F.A5">空语句</a>(仅分号)</li>
|
|
<li><a href="cpp-language-static_assert.html">static_assert</a> 声明</li>
|
|
<li>不定义类或枚举的 <a href="cpp-language-typedef.html">typedef</a> 声明及<a href="cpp-language-type_alias.html">别名</a>声明</li>
|
|
<li><a href="cpp-language-namespace.html#using_.E5.A3.B0.E6.98.8E">using 声明</a></li>
|
|
<li><a href="cpp-language-namespace.html#using_.E6.8C.87.E4.BB.A4">using 指令</a></li>
|
|
<li>恰好一条 <a href="cpp-language-return.html">return</a> 语句,当函数不是构造函数时。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx14">(C++14 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx14 t-until-cxx23">
|
|
<td>
|
|
<p><span id="relaxed-constexpr"></span></p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>函数体必须<b>不</b>含:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><a href="cpp-language-goto.html">goto</a> 语句</li>
|
|
<li>拥有除 <code>case</code> 和 <code>default</code> 之外的带有<a href="cpp-language-statements.html#.E6.A0.87.E7.AD.BE">标签</a>的语句</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><a href="cpp-language-try_catch.html">try 块</a></li>
|
|
<li><a href="cpp-language-asm.html">asm 声明</a></li>
|
|
<li><a href="cpp-language-default_initialization.html">不进行初始化</a>的变量定义</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<dl>
|
|
<dd>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>非字面类型的变量定义</li>
|
|
<li>静态或线程<a href="cpp-language-storage_duration.html">存储期</a>变量的定义</li>
|
|
</ul>
|
|
</dd>
|
|
<dd>(是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy1">=</span><span class="kw1">default</span><span class="sy4">;</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy1">=</span>delete<span class="sy4">;</span></span></span> 的函数体均不含任何上述内容。)</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx23">(C++23 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>函数体非 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy1">=</span>delete<span class="sy4">;</span></span></span> 的 <b><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 构造函数</b>必须满足下列额外要求:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>对于<a href="cpp-language-class.html">类或结构体</a>的构造函数,每个子对象和每个<a href="cpp-language-union.html#.E8.81.94.E5.90.88.E4.BD.93.E5.BC.8F.E7.9A.84.E7.B1.BB">非变体</a>非静态数据成员必须被初始化。若类是<a href="cpp-language-union.html#.E8.81.94.E5.90.88.E4.BD.93.E5.BC.8F.E7.9A.84.E7.B1.BB">联合体式的类</a>,对于其每个非空匿名联合体成员,必须恰好有一个变体成员被初始化</li>
|
|
<li>对于非空<a href="cpp-language-union.html">联合体</a>的构造函数,恰好有一个非静态数据成员被初始化</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>每个被选用于初始化非静态成员和基类的构造函数必须是 constexpr 构造函数。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p>析构函数不能为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span>,但能在常量表达式中隐式调用<a href="cpp-language-destructor.html#.E5.B9.B3.E5.87.A1.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">平凡析构函数</a>。</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>函数体非 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy1">=</span>delete<span class="sy4">;</span></span></span> 的 <b><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 析构函数</b>必须满足下列额外要求:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>每个用于销毁非静态数据成员与基类的析构函数必须是 constexpr 析构函数。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>对于 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 函数模板和类模板的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span> 函数成员,必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr 的,尽管常量表达式中不能出现这种函数的调用。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx17">
|
|
<td>
|
|
<p>因为 <a href="cpp-language-noexcept.html">noexcept</a> 运算符始终对常量表达式返回 <code>true</code>,所以它可以用于检查具体特定的 constexpr 函数调用是否采用常量表达式分支:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">constexpr</span> <span class="kw4">int</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">bool</span> b1 <span class="sy1">=</span> <span class="kw1">noexcept</span><span class="br0">(</span>f<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// false,constexpr 函数未定义</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">int</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">bool</span> b2 <span class="sy1">=</span> <span class="kw1">noexcept</span><span class="br0">(</span>f<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// true,f() 是常量表达式</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>constexpr 构造函数允许用于非字面类型的类。例如,<span class="t-lc"><a href="cpp-memory-unique_ptr.html">std::unique_ptr</a></span> 的默认构造函数是 constexpr,允许<a href="cpp-language-constant_initialization.html">常量初始化</a>。</p>
|
|
<p>引用变量可声明为 constexpr(其初始化器必须是<a href="cpp-language-constant_expression.html#.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">引用常量表达式</a>):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">static</span> <span class="kw4">constexpr</span> <span class="kw4">int</span> <span class="kw4">const</span><span class="sy3">&</span> x <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span> <span class="co1">// 到 const int 对象的 constexpr 引用</span>
|
|
<span class="co1">// (该对象拥有静态存储期,因为静态引用延长了生存期)</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>尽管在 constexpr 函数中允许 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">try</span></span></span> 块与内联汇编,但是常量表达式中仍然不允许抛出异常或执行汇编。</p>
|
|
<p>若变量拥有常量析构,则无需为调用其析构函数而生成机器码,即使其析构函数非平凡。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="cpp-keyword-constexpr.html"><tt>constexpr</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<p>计算阶乘的 C++11 constexpr 函数的定义,及扩展字符串字面量的字面类型:</p>
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <iostream></span>
|
|
<span class="co2">#include <stdexcept></span>
|
|
|
|
<span class="co1">// C++11 constexpr 函数使用递归而非迭代</span>
|
|
<span class="co1">// (C++14 constexpr 函数可使用局部变量和循环)</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">int</span> factorial<span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> n <span class="sy1"><=</span> <span class="nu0">1</span> <span class="sy4">?</span> <span class="nu0">1</span> <span class="sy4">:</span> <span class="br0">(</span>n <span class="sy2">*</span> factorial<span class="br0">(</span>n <span class="sy2">-</span> <span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="co1">// 字面类</span>
|
|
<span class="kw1">class</span> conststr <span class="br0">{</span>
|
|
<span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> p<span class="sy4">;</span>
|
|
<a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> sz<span class="sy4">;</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> N<span class="sy1">></span>
|
|
<span class="kw4">constexpr</span> conststr<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">char</span><span class="br0">(</span><span class="sy3">&</span>a<span class="br0">)</span><span class="br0">[</span>N<span class="br0">]</span><span class="br0">)</span><span class="sy4">:</span> p<span class="br0">(</span>a<span class="br0">)</span>, sz<span class="br0">(</span>N <span class="sy2">-</span> <span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
|
|
<span class="co1">// constexpr 函数通过抛异常来提示错误</span>
|
|
<span class="co1">// C++11 中,它们必须用条件运算符 ?: 来这么做</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">char</span> operator<span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> n<span class="br0">)</span> <span class="kw4">const</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> n <span class="sy1"><</span> sz <span class="sy4">?</span> p<span class="br0">[</span>n<span class="br0">]</span> <span class="sy4">:</span> <span class="kw1">throw</span> <a href="cpp-error-out_of_range.html"><span class="kw768">std::<span class="me2">out_of_range</span></span></a><span class="br0">(</span><span class="st0">""</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">constexpr</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> size<span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span> <span class="kw1">return</span> sz<span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// C++11 constexpr 函数必须把一切放在单条 return 语句中</span>
|
|
<span class="co1">// (C++14 无此要求)</span>
|
|
<span class="kw4">constexpr</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> countlower<span class="br0">(</span>conststr s, <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> n <span class="sy1">=</span> <span class="nu0">0</span>,
|
|
<a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> c <span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> n <span class="sy1">==</span> s.<span class="me1">size</span><span class="br0">(</span><span class="br0">)</span> <span class="sy4">?</span> c <span class="sy4">:</span>
|
|
<span class="st0">'a'</span> <span class="sy1"><=</span> s<span class="br0">[</span>n<span class="br0">]</span> <span class="sy3">&&</span> s<span class="br0">[</span>n<span class="br0">]</span> <span class="sy1"><=</span> <span class="st0">'z'</span> <span class="sy4">?</span> countlower<span class="br0">(</span>s, n <span class="sy2">+</span> <span class="nu0">1</span>, c <span class="sy2">+</span> <span class="nu0">1</span><span class="br0">)</span> <span class="sy4">:</span>
|
|
countlower<span class="br0">(</span>s, n <span class="sy2">+</span> <span class="nu0">1</span>, c<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="co1">// 输出要求编译时常量的函数,用于测试</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw4">int</span> n<span class="sy1">></span>
|
|
<span class="kw1">struct</span> constN
|
|
<span class="br0">{</span>
|
|
constN<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> n <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"4! = "</span> <span class="sy4">;</span>
|
|
constN<span class="sy1"><</span>factorial<span class="br0">(</span><span class="nu0">4</span><span class="br0">)</span><span class="sy1">></span> out1<span class="sy4">;</span> <span class="co1">// 在编译时计算</span>
|
|
|
|
<span class="kw4">volatile</span> <span class="kw4">int</span> k <span class="sy1">=</span> <span class="nu0">8</span><span class="sy4">;</span> <span class="co1">// 使用 volatile 防止优化</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> k <span class="sy1"><<</span> <span class="st0">"! = "</span> <span class="sy1"><<</span> factorial<span class="br0">(</span>k<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 运行时计算</span>
|
|
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"<span class="es1">\"</span>Hello, world!<span class="es1">\"</span> 里小写字母的个数是 "</span><span class="sy4">;</span>
|
|
constN<span class="sy1"><</span>countlower<span class="br0">(</span><span class="st0">"Hello, world!"</span><span class="br0">)</span><span class="sy1">></span> out2<span class="sy4">;</span> <span class="co1">// 隐式转换到常量字符串</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">4! = 24
|
|
8! = 40320
|
|
"Hello, world!" 里小写字母的个数是 9</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1911">CWG 1911</a></td>
|
|
<td>C++11</td>
|
|
<td>非字面类型不允许拥有 constexpr 构造函数</td>
|
|
<td>在常量初始化中允许</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2004">CWG 2004</a></td>
|
|
<td>C++14</td>
|
|
<td>在常量表达式中允许复制/移动有 mutable 成员的联合体</td>
|
|
<td>mutable 变体现在无法被隐式复制/移动</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2163">CWG 2163</a></td>
|
|
<td>C++14</td>
|
|
<td>constexpr 函数中禁止 goto,但允许标号</td>
|
|
<td>标号也被禁止</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2268">CWG 2268</a></td>
|
|
<td>C++14</td>
|
|
<td>cwg 2004 曾禁止了复制/移动有 mutable 成员的联合体</td>
|
|
<td>在该对象在常量表达式中创建的情况下允许</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-constant_expression.html">常量表达式</a></li>
|
|
<li><a href="cpp-language-consteval.html"><code>consteval</code></a></li>
|
|
<li><a href="cpp-language-constinit.html"><code>constinit</code></a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|