上传cppreference
This commit is contained in:
@@ -0,0 +1,589 @@
|
||||
<!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>常量表达式</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_constant_expression skin-cppreference2 action-view cpp-navbar">
|
||||
<div id="cpp-content-base">
|
||||
<div id="content"><a id="top"></a>
|
||||
<h1 id="firstHeading" class="firstHeading">常量表达式</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">
|
||||
<p>定义能在编译时求值的<a href="cpp-language-expressions.html">表达式</a>。</p>
|
||||
<p>这种表达式能用做非类型模板实参、数组大小,并用于其他要求常量表达式的语境,例如</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
||||
<a href="cpp-container-array.html"><span class="kw1268">std::<span class="me2">array</span></span></a><span class="sy1"><</span><span class="kw4">int</span>, n<span class="sy1">></span> a1<span class="sy4">;</span> <span class="co1">// 错误:n 不是常量表达式</span>
|
||||
<span class="kw4">const</span> <span class="kw4">int</span> cn <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span>
|
||||
<a href="cpp-container-array.html"><span class="kw1268">std::<span class="me2">array</span></span></a><span class="sy1"><</span><span class="kw4">int</span>, cn<span class="sy1">></span> a2<span class="sy4">;</span> <span class="co1">// OK:cn 是常量表达式</span></pre></div>
|
||||
</div>
|
||||
<h3><span class="mw-headline" id=".E6.A0.B8.E5.BF.83.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">核心常量表达式</span></h3>
|
||||
<p><i>核心(core)常量表达式</i>是求值过程中<i>不会</i>对下列任一者求值的表达式:</p>
|
||||
<ol>
|
||||
<li><a href="cpp-language-this.html"><code>this</code></a> 指针,但作为该表达式的一部分求值的 <code>constexpr</code> 函数之中的则不算</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx23"><span><span class="t-mark-rev t-since-cxx23">(C++23 起)</span> 经过静态或线程<a href="cpp-language-storage_duration.html">存储期</a>变量声明的控制流</span></li>
|
||||
<li>调用未声明为 <a href="cpp-language-constexpr.html">constexpr</a> 的函数(或构造函数)的函数调用表达式
|
||||
<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> n <span class="sy1">=</span> <a href="cpp-types-numeric_limits.html"><span class="kw344">std::<span class="me2">numeric_limits</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span><span class="sy4">::</span><span class="me2">max</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:max() 是 constexpr</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> m <span class="sy1">=</span> <a href="cpp-chrono-c-time.html"><span class="kw1011">std::<span class="me2">time</span></span></a><span class="br0">(</span><a href="cpp-types-NULL.html"><span class="kw103">NULL</span></a><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:std::time() 非 constexpr</span></pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li>对声明为 <code>constexpr</code> 但未定义的函数进行的函数调用</li>
|
||||
<li>对 <code>constexpr</code> 函数/构造函数模板实例化进行的函数调用,其中该实例化无法满足 <a href="cpp-language-constexpr.html">constexpr 函数/构造函数</a>的要求。</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> 对 <code>constexpr</code> 虚函数的函数调用,调用所用的对象不<i>可用于常量表达式</i>(见后述)且其生命期始于此表达式之外。</span></li>
|
||||
<li>会超出实现定义限制的表达式</li>
|
||||
<li>求值导致任何形式的核心语言未定义行为(包含有符号整数溢出、除以零、数组边界外的指针算术等)的表达式。是否检测标准库的未定义行为是未指明的。
|
||||
<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">double</span> d1 <span class="sy1">=</span> <span class="nu16">2.0</span><span class="sy2">/</span><span class="nu16">1.0</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">double</span> d2 <span class="sy1">=</span> <span class="nu16">2.0</span><span class="sy2">/</span><span class="nu16">0.0</span><span class="sy4">;</span> <span class="co1">// 错误:未定义</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> n <span class="sy1">=</span> <a href="cpp-types-numeric_limits.html"><span class="kw344">std::<span class="me2">numeric_limits</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span><span class="sy4">::</span><span class="me2">max</span><span class="br0">(</span><span class="br0">)</span> <span class="sy2">+</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 错误:溢出</span>
|
||||
<span class="kw4">int</span> x, y, z<span class="br0">[</span><span class="nu0">30</span><span class="br0">]</span><span class="sy4">;</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">auto</span> e1 <span class="sy1">=</span> <span class="sy3">&</span>y <span class="sy2">-</span> <span class="sy3">&</span>x<span class="sy4">;</span> <span class="co1">// 错误:未定义</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">auto</span> e2 <span class="sy1">=</span> <span class="sy3">&</span>z<span class="br0">[</span><span class="nu0">20</span><span class="br0">]</span> <span class="sy2">-</span> <span class="sy3">&</span>z<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
||||
<span class="kw4">constexpr</span> <a href="cpp-utility-bitset.html"><span class="kw1027">std::<span class="me2">bitset</span></span></a><span class="sy1"><</span><span class="nu0">2</span><span class="sy1">></span> a<span class="sy4">;</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">bool</span> b <span class="sy1">=</span> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// UB,但是否检测未指定</span></pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx17"><span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span><a href="cpp-language-lambda.html">lambda 表达式</a></span></li>
|
||||
<li>左值到右值<a href="cpp-language-implicit_conversion.html">隐式转换</a>,除非……
|
||||
<ol type="a">
|
||||
<li>应用到指代<i>可用于常量表达式</i>(见后述)的对象的非 volatile 泛左值,
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw4">const</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> tabsize <span class="sy1">=</span> <span class="nu0">50</span><span class="sy4">;</span>
|
||||
<span class="kw4">int</span> tab<span class="br0">[</span>tabsize<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK : tabsize 是常量表达式</span>
|
||||
<span class="co1">// 因为 tabsize 可用于常量表达式</span>
|
||||
<span class="co1">// 因为它有 const 限定的整数类型,且其初始化器是常量初始化器</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="nu0">50</span><span class="sy4">;</span>
|
||||
<span class="kw4">const</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> sz <span class="sy1">=</span> n<span class="sy4">;</span>
|
||||
<span class="kw4">int</span> tab2<span class="br0">[</span>sz<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误: sz 不是常量表达式</span>
|
||||
<span class="co1">// 因为 sz 不可用于常量表达式</span>
|
||||
<span class="co1">// 因为其初始化器不是常量初始化器</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li>或应用到拥有字面类型,并指代生命期始于此表达式的求值之内的非 volatile 对象</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>对 <a href="cpp-language-union.html">union</a> 的不活跃成员或其子对象实施的左值到右值<a href="cpp-language-implicit_conversion.html">隐式转换</a>或修改操作(即使它与活跃成员共享公共起始序列也是如此)</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> 应用到拥有<a href="cpp-language-default_initialization.html">不确定值</a>的对象的左值到右值隐式转换</span></li>
|
||||
<li>对活跃成员(若存在)为 mutable 的 union 调用隐式定义的复制/移动构造函数或复制/移动赋值运算符,除非该 union 对象的生命期始于此表达式的求值之内</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx17 t-until-cxx20"><span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span> <span class="t-mark-rev t-until-cxx20">(C++20 前)</span>会更改 union 的活跃成员的赋值表达式,或对重载的赋值运算符的调用</span></li>
|
||||
<li>指代引用类型的变量或数据成员的 <span class="t-spar">标识表达式</span>,除非该引用<i>可用于常量表达式</i>,或其生命始于此表达式的求值之内</li>
|
||||
<li>从 <i>cv</i> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span><span class="sy2">*</span></span></span> 转换到任何对象指针类型</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx20"><span><span class="t-mark-rev t-until-cxx20">(C++20 前)</span><a href="cpp-language-dynamic_cast.html"><code>dynamic_cast</code></a></span></li>
|
||||
<li><a href="cpp-language-reinterpret_cast.html"><code>reinterpret_cast</code></a></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx20"><span><span class="t-mark-rev t-until-cxx20">(C++20 前)</span>伪析构函数调用</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx14"><span><span class="t-mark-rev t-until-cxx14">(C++14 前)</span>自增或自减运算符</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx14">
|
||||
<div>
|
||||
<p><span class="t-mark-rev t-since-cxx14">(C++14 起)</span> 修改对象,除非该对象拥有非 volatile 字面类型,且其生命期始于此表达式的求值之内</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> incr<span class="br0">(</span><span class="kw4">int</span><span class="sy3">&</span> n<span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw1">return</span> <span class="sy2">++</span>n<span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">int</span> k<span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> x <span class="sy1">=</span> incr<span class="br0">(</span>k<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:incr(k) 不是核心常量表达式</span>
|
||||
<span class="co1">// 因为 k 的生命期始于表达式 incr(k) 之外</span>
|
||||
<span class="kw1">return</span> x<span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> h<span class="br0">(</span><span class="kw4">int</span> k<span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw4">int</span> x <span class="sy1">=</span> incr<span class="br0">(</span>k<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:不要求 x 以核心常量表达式初始化</span>
|
||||
<span class="kw1">return</span> x<span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> y <span class="sy1">=</span> h<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:以值 2 初始化 y</span>
|
||||
<span class="co1">// h(1) 是核心常量表达式</span>
|
||||
<span class="co1">// 因为 k 的生命期始于表达式 h(1) 之内</span></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> 对于生存期不在此表达式的求值内开始的对象的析构函数调用或伪析构函数调用</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx20"><span><span class="t-mark-rev t-until-cxx20">(C++20 前)</span>应用到多态类型泛左值的 <a href="cpp-language-typeid.html"><code>typeid</code></a> 表达式</span></li>
|
||||
<li><a href="cpp-language-new.html">new 表达式</a><span class="t-rev-inl t-since-cxx20"><span>,除非选择的<a href="cpp-memory-new-operator_new.html">分配函数</a>是全局可替换分配函数且此表达式的求值内解分配其所分配的存储</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span></li>
|
||||
<li><a href="cpp-language-delete.html">delete 表达式</a><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 class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span>调用 <span class="t-lc"><a href="cpp-memory-allocator-allocate.html">std::allocator<T>::allocate</a></span> ,除非于此表达式的求值内解分配其所分配的存储</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span>调用 <span class="t-lc"><a href="cpp-memory-allocator-deallocate.html">std::allocator<T>::deallocate</a></span> ,除非它解分配于此表达式的求值内分配的存储区域</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span><a href="cpp-language-coroutines.html#co_await">await 表达式</a>或 <a href="cpp-language-coroutines.html#co_yield">yield 表达式</a></span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span>结果未指定<a href="cpp-language-operator_comparison.html#.E4.B8.89.E8.B7.AF.E6.AF.94.E8.BE.83">三路比较</a></span></li>
|
||||
<li>结果未指明的相等或关系运算符</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-until-cxx14"><span><span class="t-mark-rev t-until-cxx14">(C++14 前)</span>赋值或复合赋值运算符</span></li>
|
||||
<li>throw 表达式</li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> <a href="cpp-language-asm.html">汇编声明</a></span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx14"><span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span> 宏 <span class="t-lc"><a href="cpp-utility-variadic-va_arg.html">va_arg</a></span> 的调用,是否能求值宏 <span class="t-lc"><a href="cpp-utility-variadic-va_start.html">va_start</a></span> 是未指定的</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx23"><span><span class="t-mark-rev t-since-cxx23">(C++23 起)</span> <a href="cpp-language-goto.html"><code>goto</code></a> 语句</span></li>
|
||||
<li class="t-rev-inl t-rev-inl-noborder t-since-cxx20"><span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span>会抛出异常的 <a href="cpp-language-dynamic_cast.html"><code>dynamic_cast</code></a> 或 <a href="cpp-language-typeid.html"><code>typeid</code></a> 表达式</span></li>
|
||||
<li>lambda 表达式中,提及 <code>this</code> 或提及定义于该 lambda 之外的变量,若它是一次 ODR 式使用
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw4">const</span> <span class="kw4">int</span> n<span class="sy1">=</span><span class="nu0">0</span><span class="sy4">;</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> j<span class="sy1">=</span><span class="sy2">*</span><span class="sy3">&</span>n<span class="sy4">;</span> <span class="co1">// OK:lambda 表达式之外</span>
|
||||
<span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">{</span> <span class="kw4">constexpr</span> <span class="kw4">int</span> i<span class="sy1">=</span>n<span class="sy4">;</span> <span class="co1">// OK:'n' 未被 ODR 式使用且未在此处被俘获。</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> j<span class="sy1">=</span><span class="sy2">*</span><span class="sy3">&</span>n<span class="sy4">;</span><span class="co1">// 非良构:'&n' ODR 式使用了 'n'。</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx17">
|
||||
<td>
|
||||
<p>注意,若 ODR 式使用发生于对闭包的函数调用中,则它不涉指 <code>this</code> 或外围变量,因为它所访问的是该闭包的数据成员</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="co1">// OK:'v' 与 'm' 被 ODR 式使用,但未出现于嵌套于 lambda 内的常量表达式中</span>
|
||||
<span class="kw4">auto</span> monad <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> v<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">{</span><span class="kw1">return</span> v<span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="kw4">auto</span> bind <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> m<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> fvm<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> fvm<span class="br0">(</span>m<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="co1">// 在常量表达式求值中,创建对自动对象的俘获是 OK 的。</span>
|
||||
static_assert<span class="br0">(</span>bind<span class="br0">(</span>monad<span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span><span class="br0">(</span>monad<span class="br0">)</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1">==</span> monad<span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></pre></div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ol>
|
||||
<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>注意:<i>核心常量表达式</i>本身并无任何直接的语义含义:表达式必须为常量表达式的子集之一(见后述),才可以在特定语境中使用。</p>
|
||||
<h3><span class="mw-headline" id=".E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">常量表达式</span></h3>
|
||||
<p><i>常量表达式(constant expression)</i>是</p>
|
||||
<ul>
|
||||
<li>指代下列之一的<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-rev-inl t-since-cxx14"><span>泛左值</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span><i>核心常量表达式</i></li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>拥有静态存储期且非临时的对象,或</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx14">
|
||||
<td>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>拥有静态存储期的临时对象,但其值满足下文对纯右值的约束,或</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li><span class="t-rev-inl t-since-cxx20"><span>非<a href="cpp-language-consteval.html">立即</a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>函数</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<ul>
|
||||
<li>其值满足下列约束的纯右值<i>核心常量表达式</i>:</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>若其值是类类型对象,则其每个引用类型的非静态数据成员均指代满足上述对<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-rev-inl t-since-cxx14"><span>泛左值</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>约束的实体</li>
|
||||
<li>若其值为指针类型,则它保有</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>拥有静态存储期的对象的地址</li>
|
||||
<li>拥有静态存储期的对象的末尾后一位置的地址</li>
|
||||
<li><span class="t-rev-inl t-since-cxx20"><span>非<a href="cpp-language-consteval.html">立即</a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>函数的地址</li>
|
||||
<li>空指针值</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>若其值是成员函数指针类型,则它不代表<a href="cpp-language-consteval.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>若其值具有类或数组类型,则每个子对象均满足这些对值的约束</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<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>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw4">void</span> test<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
<span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">int</span> a <span class="sy1">=</span> <a href="cpp-numeric-random-random_device.html"><span class="kw1486">std::<span class="me2">random_device</span></span></a><span class="br0">{</span><span class="br0">}</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> ra <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// OK:a 是泛左值常量表达式</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> ia <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 错误:a 不是纯右值常量表达式</span>
|
||||
|
||||
<span class="kw4">const</span> <span class="kw4">int</span> b <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> rb <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// 错误:b 不是泛左值常量表达式</span>
|
||||
<span class="kw4">constexpr</span> <span class="kw4">int</span> ib <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// OK:b 是纯右值常量表达式</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
<h4><span class="mw-headline" id=".E6.95.B4.E5.9E.8B.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">整型常量表达式</span></h4>
|
||||
<p><i>整型常量表达式</i>是隐式转换成纯右值的整型或无作用域枚举类型的表达式,其中被转换的表达式是<i>核心常量表达式</i>。若将类类型表达式用在期待整型常量表达式之处,则表达式将被<a href="cpp-language-implicit_conversion.html">按语境隐式转换</a>成整型或无作用域枚举类型。</p>
|
||||
<p>下列语境要求<i>整型常量表达式</i>:</p>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-until-cxx14">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-array.html">数组边界</a></li>
|
||||
<li><a href="cpp-language-new.html">new 表达式</a>中首个以外的维度</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-until-cxx14">(C++14 前)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li><a href="cpp-language-bit_field.html">位域长度</a></li>
|
||||
<li>底层类型未固定时的枚举初始化器</li>
|
||||
<li><a href="cpp-language-alignas.html">对齐</a>。</li>
|
||||
</ul>
|
||||
<h4><span class="mw-headline" id=".E7.BB.8F.E8.BD.AC.E6.8D.A2.E7.9A.84.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">经转换的常量表达式</span></h4>
|
||||
<p><code>T</code> 类型的<i>经转换的常量表达式</i>是<a href="cpp-language-implicit_conversion.html">隐式转换</a>到 T 类型的表达式,其中被转换后表达式是常量表达式,且隐式转换序列只含有:</p>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>constexpr 用户定义转换(故类能用于期待整数类型之处)</li>
|
||||
<li>左值到右值转换</li>
|
||||
<li>整型提升</li>
|
||||
<li>非窄化整型转换</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx17">
|
||||
<td>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>数组到指针转换</li>
|
||||
<li>函数到指针转换</li>
|
||||
<li>函数指针转换(指向 noexcept 函数的指针到指向函数的指针)</li>
|
||||
<li>限定性转换</li>
|
||||
<li>源自 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span> 的空指针转换</li>
|
||||
<li>源自 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span> 的空成员指针转换</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>而若发生任何<a href="cpp-language-reference_initialization.html">引用绑定</a>,则它是直接绑定(非构造临时对象者)</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>下列语境要求<i>经转换的常量表达式</i>:</p>
|
||||
<ul>
|
||||
<li><a href="cpp-language-switch.html">case 表达式</a></li>
|
||||
<li>底层类型已固定时的<a href="cpp-language-enum.html">枚举项初始化器</a></li>
|
||||
</ul>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx14">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-array.html">数组边界</a></li>
|
||||
<li><a href="cpp-language-new.html">new 表达式</a>中,第一维以外的维度</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li><span class="t-rev-inl t-until-cxx17"><span>整型与枚举</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span>非类型<a href="cpp-language-template_parameters.html">模板实参</a>。</li>
|
||||
</ul>
|
||||
<p><i>按语境转换的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> 类型常量表达式</i>是<a href="cpp-language-implicit_conversion.html#.E6.8C.89.E8.AF.AD.E5.A2.83.E8.BD.AC.E6.8D.A2">按语境转换到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span></a> 的表达式,其中转换后的表达式是常量表达式,且转换序列只含上述转换。</p>
|
||||
<p>下列语境要求<i>按语境转换的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> 类型常量表达式</i>:</p>
|
||||
<ul>
|
||||
<li><a href="cpp-language-noexcept_spec.html"><code>noexcept</code> 规定</a></li>
|
||||
</ul>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-until-cxx23">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-static_assert.html"><code>static_assert</code> 声明</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-until-cxx23">(C++23 前)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx17 t-until-cxx23">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-if.html#constexpr_if">constexpr <code>if</code> 语句</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span><br />
|
||||
<span class="t-mark-rev t-until-cxx23">(C++23 前)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-explicit.html">条件性 <code>explicit</code> 说明符</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4><span class="mw-headline" id=".E5.8E.86.E5.8F.B2.E7.B1.BB.E5.88.AB">历史类别</span></h4>
|
||||
<p>下列常量表达式的类别从 C++14 起不再于标准中使用:</p>
|
||||
<ul>
|
||||
<li><i>字面常量表达式</i>是非指针字面类型(经语境所要求的转换后)的纯右值<i>核心常量表达式</i>。数组或类类型的字面常量表达式要求每个子对象以常量表达式初始化。</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><i>引用常量表达式</i>是指代具有静态存储期的对象或指代函数的左值核心常量表达式。</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><i>地址常量表达式</i>是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-types-nullptr_t.html"><span class="kw102">std::<span class="me2">nullptr_t</span></span></a></span></span> 类型或指针类型(经语境所要求的转换后)的纯右值核心常量表达式,它指向具有静态存储期的对象,指向具有静态存储期的数组末尾后一位置,指向函数,或为空指针。</li>
|
||||
</ul>
|
||||
<h3><span class="mw-headline" id=".E5.8F.AF.E7.94.A8.E4.BA.8E.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">可用于常量表达式</span></h3>
|
||||
<p>上述列表中,变量在 <i>P</i> 点<i>可用于常量表达式</i>,</p>
|
||||
<ul>
|
||||
<li>若该变量是</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>constexpr 变量,或</li>
|
||||
<li>拥有下列类型的<a href="cpp-language-constant_initialization.html">常量初始化的</a>变量</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li>引用类型,或</li>
|
||||
<li>const 限定的整数或枚举类型。</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<ul>
|
||||
<li>而该变量的定义从 <i>P</i> 可达</li>
|
||||
</ul>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<ul>
|
||||
<li>而若 <i>P</i> 不在与该变量定义相同的翻译单元中(即定义是<a href="cpp-language-modules.html">导入</a>的),则该变量未被初始化为指向或指代,或拥有(可能递归的)子对象或成员指向或指代可用于常量表达式的<a href="cpp-language-tu_local.html">翻译单元局部实体</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>对象或引用<i>可用于常量表达式</i>,若它是</p>
|
||||
<ul>
|
||||
<li><i>可用于常量表达式</i>的变量,或</li>
|
||||
<li><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> <a href="cpp-language-template_parameters.html#.E9.9D.9E.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82">模板形参对象</a>,或</li>
|
||||
<li>字符串字面量对象,或</li>
|
||||
<li>以上任一者的非 mutable 子对象或引用成员,或</li>
|
||||
<li>非 volatile 的 const 限定整数类或枚举类型的,以常量表达式初始化的完整临时对象。</li>
|
||||
</ul>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw4">const</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> sz <span class="sy1">=</span> <span class="nu0">10</span><span class="sy4">;</span> <span class="co1">// sz 可用于常量表达式</span></pre></div>
|
||||
</div>
|
||||
<h3><span class="mw-headline" id=".E6.98.8E.E6.98.BE.E5.B8.B8.E9.87.8F.E6.B1.82.E5.80.BC.E7.9A.84.E8.A1.A8.E8.BE.BE.E5.BC.8F">明显常量求值的表达式</span></h3>
|
||||
<p>下列表达式(包括到目标类型的转换)是<i>明显常量求值</i>的:</p>
|
||||
<ul>
|
||||
<li>语法上要求常量表达式处,包括</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li><a href="cpp-language-array.html">数组边界</a></li>
|
||||
<li><a href="cpp-language-new.html">new 表达式</a>中第一维以外的数组长度</li>
|
||||
<li><a href="cpp-language-bit_field.html">位域长度</a></li>
|
||||
<li><a href="cpp-language-enum.html">枚举项初始化器</a></li>
|
||||
<li><a href="cpp-language-alignas.html">对齐</a></li>
|
||||
<li><a href="cpp-language-switch.html"><code>case</code> 表达式</a></li>
|
||||
<li>非类型<a href="cpp-language-template_parameters.html">模板实参</a></li>
|
||||
<li><a href="cpp-language-noexcept_spec.html"><code>noexcept</code> 说明</a>中的表达式</li>
|
||||
<li><a href="cpp-language-static_assert.html"><code>static_assert</code> 声明</a>中的表达式</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li><a href="cpp-language-explicit.html">条件性 <code>explicit</code> 说明符</a>中的表达式</li>
|
||||
</ul>
|
||||
</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-cxx17">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-if.html#constexpr_if">constexpr if 语句</a>中的条件</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-consteval.html">立即调用</a></li>
|
||||
<li><a href="cpp-language-constraints.html#.E6.A6.82.E5.BF.B5">概念</a>定义、<a href="cpp-language-constraints.html#.E5.B5.8C.E5.A5.97.E8.A6.81.E6.B1.82">嵌套要求</a>及<a href="cpp-language-constraints.html#requires_.E5.AD.90.E5.8F.A5">requires 子句</a>中的约束表达式</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li>可用于常量表达式的变量的初始化器,包括</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dd>
|
||||
<ul>
|
||||
<li><a href="cpp-language-constexpr.html">constexpr 变量</a>的初始化器</li>
|
||||
<li><a href="cpp-language-reference.html">引用</a>和 const 限定的整数或枚举类型的变量的初始化器,若该初始化器为常量表达式</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<ul>
|
||||
<li>静态及线程局域变量的初始化器,若该初始化器的所有子表达式(含构造函数调用和隐式转换)均为常量表达式(即该初始化器为<a href="cpp-language-constant_initialization.html">常量初始化器</a>)</li>
|
||||
</ul>
|
||||
<p>注意最后两种情况的语境亦接受非常量表达式。</p>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx20">
|
||||
<td>
|
||||
<p>能用 <span class="t-lc">std::is_constant_evaluated</span> <span class="t-rev-inl t-since-cxx23"><span>和 <a href="cpp-language-if.html#consteval_if"><code>if consteval</code></a></span> <span><span class="t-mark-rev t-since-cxx23">(C++23 起)</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.B8.B8.E9.87.8F.E6.B1.82.E5.80.BC.E6.89.80.E9.9C.80.E8.A6.81.E7.9A.84.E5.87.BD.E6.95.B0.E4.B8.8E.E5.8F.98.E9.87.8F">常量求值所需要的函数与变量</span></h3>
|
||||
<p>下列表达式或转换为<i>潜在常量求值</i>的:</p>
|
||||
<ul>
|
||||
<li>明显常量求值的表达式</li>
|
||||
<li>潜在求值的表达式</li>
|
||||
<li>花括号初始化器列表的立即子表达式(可能需要常量求值确定转换是否为<a href="cpp-language-list_initialization.html#.E7.AA.84.E5.8C.96.E8.BD.AC.E6.8D.A2">窄化</a>)</li>
|
||||
<li>出现于<a href="cpp-language-templates.html#.E6.A8.A1.E6.9D.BF.E5.8C.96.E5.AE.9E.E4.BD.93">模板化实体</a>内的取址(一元 <code>&</code>)表达式(可能需要常量求值确定这种表达式是否为<a href="cpp-language-dependent_name.html#.E5.80.BC.E5.BE.85.E5.86.B3.E8.A1.A8.E8.BE.BE.E5.BC.8F">值待决</a>)</li>
|
||||
<li>上述之一的子表达式,除了嵌套的<a href="cpp-language-expressions.html#.E4.B8.8D.E6.B1.82.E5.80.BC.E8.A1.A8.E8.BE.BE.E5.BC.8F">不求值操作数</a>的子表达式</li>
|
||||
</ul>
|
||||
<p>若函数为 constexpr 函数且为潜在常量求值的表达式所<a href="cpp-language-definition.html#.E6.8C.87.E5.90.8D.E5.87.BD.E6.95.B0">指名</a>,则它为<i>常量求值所需要</i>。</p>
|
||||
<p>若变量为 constexpr 变量或非 volatile 的 const 限定的整数类型或引用类型的变量,且指代它的<a href="cpp-language-expressions.html#.E5.88.9D.E7.AD.89.E8.A1.A8.E8.BE.BE.E5.BC.8F">标识表达式</a>被潜在常量求值,则它为<i>常量求值所需要</i>。</p>
|
||||
<p>预置的函数的定义及<a href="cpp-language-function_template.html">函数模板</a>特化<span class="t-rev-inl t-since-cxx14"><span>或<a href="cpp-language-variable_template.html">变量模板</a>特化</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>的实例化会被触发,若该函数<span class="t-rev-inl t-since-cxx14"><span>或变量</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>为常量求值所需要。</p>
|
||||
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
||||
<p>不容许实现将库函数声明为 <code>constexpr</code>,除非标准说该函数为 <code>constexpr</code>。</p>
|
||||
<p>常量表达式中不容许<a href="cpp-language-copy_elision.html">具名返回值优化</a>( NRVO ),而返回值优化( RVO )是强制要求的。</p>
|
||||
<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/issue1313">CWG 1313</a></td>
|
||||
<td>C++11</td>
|
||||
<td>容许未定义行为;且禁止所有指针减法</td>
|
||||
<td>禁止 UB ;同数组内的指针减法 OK</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1581">CWG 1581</a></td>
|
||||
<td>C++11</td>
|
||||
<td>未要求定义或实例化常量求值所需要的函数</td>
|
||||
<td>已要求</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1952">CWG 1952</a></td>
|
||||
<td>C++11</td>
|
||||
<td>要求诊断标准库未定义行为</td>
|
||||
<td>未指定是否诊断库 UB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2167">CWG 2167</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/issue2299">CWG 2299</a></td>
|
||||
<td>C++14</td>
|
||||
<td><a href="cpp-header-cstdarg.html"><tt><cstdarg></tt></a> 中的宏能否用于常量求值不明确</td>
|
||||
<td>禁止 <code>va_arg</code> ,未指定 <code>va_start</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2490">CWG 2490</a></td>
|
||||
<td>C++20</td>
|
||||
<td>常量求值中的(伪)析构函数调用缺少限制</td>
|
||||
<td>添加了限制</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
||||
<table class="t-dsc-begin">
|
||||
<tr class="t-dsc">
|
||||
<td><a href="cpp-language-constexpr.html"><code>constexpr</code> 说明符</a><span class="t-mark-rev t-since-cxx11">(C++11)</span></td>
|
||||
<td>指定变量或函数的值能在编译时计算</td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-types-is_literal_type.html"><span class="t-lines"><span>is_literal_type</span></span></a></div>
|
||||
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span><span><span class="t-mark-rev t-deprecated-cxx17">(C++17 中弃用)</span></span><span><span class="t-mark-rev t-until-cxx20">(C++20 中移除)</span></span></span></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>检查类型是否为字面类型<br />
|
||||
<span class="t-mark">(类模板)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="visualClear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user