563 lines
88 KiB
HTML
563 lines
88 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>制约与概念</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_experimental_constraints 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-experimental.html">experimental</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p><span style="font-size:0.7em; line-height:130%">此页面描述实验性的新语言特性。对于用于标准库规范的具名类型要求,见<a href="cpp-named_req.html">具名要求</a>。</span></p>
|
|
<p><a href="cpp-language-class_template.html">类模板</a>、<a href="cpp-language-function_template.html">函数模板</a>及非模板函数(常为类模板成员)可以与<i>制约</i>关联,制约指定模板实参上的要求,这能用于选择最准确的函数重载和模板特化。</p>
|
|
<p>制约亦可用于限制变量声明和函数返回类型中的自动类型推导,为只有满足指定要求的类型。</p>
|
|
<p>这种要求的具名集合被称为<i>概念</i>。每个概念都是谓词,于编译时求值,并成为模板接口的一部分,它在其中用作制约:</p>
|
|
<div class="t-example">
|
|
<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 <string></span>
|
|
<span class="co2">#include <locale></span>
|
|
<span class="kw1">using</span> <span class="kw1">namespace</span> std<span class="sy4">::</span><span class="me2">literals</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 概念 "EqualityComparable" 的声明,任何有该类型值 a 和 b ,</span>
|
|
<span class="co1">// 而表达式 a==b 可编译而其结果可转换为 bool 的 T 类型满足它</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> EqualityComparable <span class="sy1">=</span> requires<span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="br0">{</span> a <span class="sy1">==</span> b <span class="br0">}</span> <span class="sy2">-</span><span class="sy1">></span> <span class="kw4">bool</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span>EqualityComparable<span class="sy3">&&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 有制约函数模板的声明</span>
|
|
<span class="co1">// template<typename T></span>
|
|
<span class="co1">// void f(T&&) requires EqualityComparable<T>; // 相同的长形式</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
f<span class="br0">(</span><span class="st0">"abc"</span>s<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK : std::string 为 EqualityComparable</span>
|
|
f<span class="br0">(</span><a href="cpp-locale-use_facet.html"><span class="kw1897">std::<span class="me2">use_facet</span></span></a><span class="sy1"><</span><a href="cpp-locale-ctype.html"><span class="kw1938">std::<span class="me2">ctype</span></span></a><span class="sy1"><</span><span class="kw4">char</span><span class="sy1">>></span><span class="br0">(</span><a href="cpp-locale-locale.html"><span class="kw1894">std::<span class="me2">locale</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="co1">// 错误:非 EqualityComparable </span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>在编译时检测制约违规,早于模板实例化处理,这导致错误信息更易理解。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><a href="cpp-container-list.html"><span class="kw1275">std::<span class="me2">list</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> l <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">3</span>,<span class="sy2">-</span><span class="nu0">1</span>,<span class="nu0">10</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<a href="cpp-algorithm-sort.html"><span class="kw1618">std::<span class="me2">sort</span></span></a><span class="br0">(</span>l.<span class="me1">begin</span><span class="br0">(</span><span class="br0">)</span>, l.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">//无概念的典型编译器诊断:</span>
|
|
<span class="co1">// invalid operands to binary expression ('std::_List_iterator<int>' and</span>
|
|
<span class="co1">// 'std::_List_iterator<int>')</span>
|
|
<span class="co1">// std::__lg(__last - __first) * 2);</span>
|
|
<span class="co1">// ~~~~~~ ^ ~~~~~~~</span>
|
|
<span class="co1">// …… 50 行输出……</span>
|
|
<span class="co1">//</span>
|
|
<span class="co1">//有概念的典型编译器诊断:</span>
|
|
<span class="co1">// error: cannot call std::sort with std::_List_iterator<int></span>
|
|
<span class="co1">// note: concept RandomAccessIterator<std::_List_iterator<int>> was not satisfied</span></pre></div>
|
|
</div>
|
|
<p>概念的目的是模拟语义类别( Number 、 Range 、 RegularFunction )而非语法制约( HasPlus 、 Array )。按照 <a rel="nofollow" class="external text" href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#t20-avoid-concepts-without-meaningful-semantics">ISO C++ 核心方针 T.20</a> ,“与语法制约相反,指定有意义语义的能力是真概念的定义性特征。”</p>
|
|
<h3><span class="mw-headline" id=".E5.8D.A0.E4.BD.8D.E7.AC.A6">占位符</span></h3>
|
|
<p>无制约占位符 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span></span></span> 与拥有形式 <span class="t-spar">concept-name</span> <code><b><</b></code> <span class="t-spar">template-argument-list</span><span class="t-mark">(optional)</span><code><b>></b></code> 的<i>有制约占位符</i>,是要被推导的类型的占位符。</p>
|
|
<p>占位符可出现于变量声明(该情况下它们从初始化器推导)或于函数返回类型(该情况下它们从 return 语句推导)</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><a href="cpp-utility-pair.html"><span class="kw1096">std::<span class="me2">pair</span></span></a><span class="sy1"><</span><span class="kw4">auto</span>, <span class="kw4">auto</span><span class="sy1">></span> p2 <span class="sy1">=</span> <a href="cpp-utility-pair-make_pair.html"><span class="kw1097">std::<span class="me2">make_pair</span></span></a><span class="br0">(</span><span class="nu0">0</span>, <span class="st0">'a'</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 第一个 auto 是 int,</span>
|
|
<span class="co1">// 第二个 auto 是 char</span>
|
|
|
|
Sortable x <span class="sy1">=</span> f<span class="br0">(</span>y<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// x 的类型从 f 的返回类型推导,仅若类型满足制约 Sortable 才能编译</span>
|
|
|
|
<span class="kw4">auto</span> f<span class="br0">(</span>Container<span class="br0">)</span> <span class="sy2">-</span><span class="sy1">></span> Sortable<span class="sy4">;</span> <span class="co1">// 返回类型从 return 语句推导,仅若类型满足 Sortable 才能编译</span></pre></div>
|
|
</div>
|
|
<p>占位符亦可出现于形参中,该情况下它们将函数声明转化为模板声明(若占位符有制约,则模板声明有制约)</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span>size_t N<span class="sy1">></span> concept <span class="kw4">bool</span> Even <span class="sy1">=</span> <span class="br0">(</span>N<span class="sy2">%</span><span class="nu19">2</span> <span class="sy1">==</span> <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</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">auto</span>, Even<span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 这是有二个形参的模板:</span>
|
|
<span class="co1">// 无制约类型形参和有制约非类型形参</span></pre></div>
|
|
</div>
|
|
<p>有制约占位符可用于 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span></span></span> 能用的任何位置,例如在泛型 lambda 声明中</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">auto</span> gl <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span>Assignable<span class="sy3">&</span> a, <span class="kw4">auto</span><span class="sy2">*</span> b<span class="br0">)</span> <span class="br0">{</span> a <span class="sy1">=</span> <span class="sy2">*</span>b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.BC.A9.E5.86.99.E7.9A.84.E6.A8.A1.E6.9D.BF">缩写的模板</span></h3>
|
|
<p>若函数参数列表中出现一或多个占位符,则函数声明实际上是函数模板声明,其模板形参列表以出现顺序,为每个单独的占位符包含一个虚设的形参</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 短形式</span>
|
|
<span class="kw4">void</span> g1<span class="br0">(</span><span class="kw4">const</span> EqualityComparable<span class="sy2">*</span>, Incrementable<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式:</span>
|
|
<span class="co1">// template<EqualityComparable T, Incrementable U> void g1(const T*, U&);</span>
|
|
<span class="co1">// 更长形式:</span>
|
|
<span class="co1">// template<typename T, typename U></span>
|
|
<span class="co1">// void g1(const T*, U&) requires EqualityComparable<T> && Incrementable<U>;</span>
|
|
|
|
<span class="kw4">void</span> f2<span class="br0">(</span><a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span><span class="kw4">auto</span><span class="sy2">*</span><span class="sy1">></span>...<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<typename... T> void f2(std::vector<T*>...);</span>
|
|
|
|
<span class="kw4">void</span> f4<span class="br0">(</span><span class="kw4">auto</span> <span class="br0">(</span>auto<span class="sy4">::</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">auto</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<typename T, typename U, typename V> void f4(T (U::*)(V));</span></pre></div>
|
|
</div>
|
|
<p>等价的有制约类型指定符所引入的所有占位符拥有同一虚设模板形参。然而,每个无制约指定符( <code>auto</code> )始终引入一个相异的模板形参</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> f0<span class="br0">(</span>Comparable a, Comparable<span class="sy2">*</span> b<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<Comparable T> void f0(T a, T* b);</span>
|
|
|
|
<span class="kw4">void</span> f1<span class="br0">(</span><span class="kw4">auto</span> a, <span class="kw4">auto</span><span class="sy2">*</span> b<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<typename T, typename U> f1(T a, U* b);</span></pre></div>
|
|
</div>
|
|
<p>函数模板与类模板都能用<i>模板引入</i>声明,它有语法 <span class="t-spar">concept-name</span> <code><b>{</b></code> <span class="t-spar">parameter-list</span><span class="t-mark">(可选)</span><code><b>}</b></code> ,此情况中不需要关键词 <code>template</code> :来自模板引入的 <span class="t-spar">parameter-list</span> 的每个形参都成为模板形参,其种类(类型、非类型、模板)以具名概念中对应形参的种类确定。</p>
|
|
<p>除了声明模板,模板引入关联一个<i>谓词制约</i>(见后述),它指名(对于变量概念)或调用(对于函数概念)该引入所指名的概念。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1">EqualityComparable<span class="br0">{</span>T<span class="br0">}</span> <span class="kw1">class</span> Foo<span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<EqualityComparable T> class Foo;</span>
|
|
<span class="co1">// 更长形式: template<typename T> requires EqualityComparable<T> class Foo;</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T, <span class="kw4">int</span> N, <span class="kw1">typename</span>... <span class="me1">Xs</span><span class="sy1">></span> concept <span class="kw4">bool</span> Example <span class="sy1">=</span> ...<span class="sy4">;</span>
|
|
Example<span class="br0">{</span>A, B, ...<span class="me1">C</span><span class="br0">}</span> <span class="kw1">struct</span> S1<span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<class A, int B, class... C> requires Example<A,B,C...> struct S1;</span></pre></div>
|
|
</div>
|
|
<p>对于函数模板,模板引入能与占位符组合:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1">Sortable<span class="br0">{</span>T<span class="br0">}</span> <span class="kw4">void</span> f<span class="br0">(</span>T, <span class="kw4">auto</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 长形式: template<Sortable T, typename U> void f(T, U);</span>
|
|
<span class="co1">// 另一种只用占位符的形式: void f(Sortable, auto);</span></pre></div>
|
|
</div>
|
|
<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=".E6.A6.82.E5.BF.B5">概念</span></h3>
|
|
<p>概念是具名要求集合。概念的定义出现于命名空间作用域,并拥有<a href="cpp-language-function_template.html">函数模板</a>定义(该情况下称为<i>函数概念</i>)或<a href="cpp-language-variable_template.html">变量模板</a>定义(该情况下称为<i>变量概念</i>)的形式。仅有的区别是关键词 <span class="t-c"><span class="mw-geshi cpp source-cpp">concept</span></span> 出现于 <span class="t-spar">decl-specifier-seq</span> 中:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 来自标准(范围 TS )的变量概念</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Derived <span class="sy1">=</span> <a href="cpp-types-is_base_of.html"><span class="kw590">std::<span class="me2">is_base_of</span></span></a><span class="sy1"><</span>U, T<span class="sy1">></span><span class="sy4">::</span><span class="me2">value</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 来自标准(范围 TS )的函数概念</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> EqualityComparable<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> requires<span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span> <span class="br0">{</span>a <span class="sy1">==</span> b<span class="br0">}</span> <span class="sy2">-</span><span class="sy1">></span> Boolean<span class="sy4">;</span> <span class="br0">{</span>a <span class="sy3">!</span><span class="sy1">=</span> b<span class="br0">}</span> <span class="sy2">-</span><span class="sy1">></span> Boolean<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>下列限制应用于函数概念:</p>
|
|
<ul>
|
|
<li>不允许 <code>inline</code> 与 <code>constexpr</code> ,函数自动为 <code>inline</code> 与 <code>constexpr</code></li>
|
|
<li>不允许 <code>friend</code> 与 <code>virtual</code></li>
|
|
<li>不允许异常规定,函数自动为 <code>noexcept(true)</code> 。</li>
|
|
<li>不能声明并延迟定义,不能重声明</li>
|
|
<li>返回类型必须是 <code>bool</code></li>
|
|
<li>不允许返回类型推导</li>
|
|
<li>参数列表必须为空</li>
|
|
<li>函数体必须仅由一条 <code>return</code> 语句组成,其参数必须是一条<i>制约表达式</i>(谓词制约、其他制约的合取/析取或 requires 表达式,见后述)</li>
|
|
</ul>
|
|
<p>下列限制应用于变量概念:</p>
|
|
<ul>
|
|
<li>必须有类型 <code>bool</code></li>
|
|
<li>不能声明为无初始化器</li>
|
|
<li>不允许 <code>constexpr</code> ,变量自动为 <code>constexpr</code></li>
|
|
<li>初始化器必须是制约表达式(谓词制约、其他制约的合取/析取或 requires 表达式,见后述)</li>
|
|
</ul>
|
|
<p>概念不能在函数体内或变量初始化器内递归地指涉自身:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> F<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> F<span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy4">::</span><span class="me2">type</span><span class="sy1">></span><span class="br0">(</span><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="kw1">typename</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> V <span class="sy1">=</span> V<span class="sy1"><</span>T<span class="sy2">*</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 错误</span></pre></div>
|
|
</div>
|
|
<p>概念定义不能有关联的制约。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C1 <span class="sy1">=</span> <span class="kw2">true</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span>C1 T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Error1 <span class="sy1">=</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="co1">// 错误:C1 T 声明了一个关联的制约</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> requires C1<span class="sy1"><</span>T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Error2 <span class="sy1">=</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="co1">// 错误:requires 子句声明了一个关联的制约</span></pre></div>
|
|
</div>
|
|
<p>不允许概念的显式实例化、显式特化或部分特化(不能更改制约的原初定义的意义)。</p>
|
|
<h3><span class="mw-headline" id=".E5.88.B6.E7.BA.A6">制约</span></h3>
|
|
<p>制约是一系列逻辑运算,它指定模板实参上的要求。它们可出现于 <i>requires 表达式</i>(见后述)中,及直接作为概念的体。</p>
|
|
<p>制约有 9 种类型:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 合取</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 析取</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 谓词制约</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 表达式制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 类型制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<div class="t-li1"><span class="t-li">6)</span> 隐式转换制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<div class="t-li1"><span class="t-li">7)</span> 实参推导制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<div class="t-li1"><span class="t-li">8)</span> 异常制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<div class="t-li1"><span class="t-li">9)</span> 参数化制约(仅在 <i>requires 表达式</i>中)</div>
|
|
<p>前三个类型的制约可以直接作为概念的体,或作为随即的 requires 子句出现:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
requires <span class="co1">// requires 子句(随即的制约)</span>
|
|
sizeof<span class="br0">(</span>T<span class="br0">)</span> <span class="sy1">></span> <span class="nu0">1</span> <span class="sy3">&&</span> get_value<span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span> <span class="co1">// 二个谓词制约的合取</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>附着多个制约到同一声明时,总制约是按下列顺序的合取:<i>模板引入</i>所引入的制约、按出现顺序的每个模板形参的制约、模板形参列表后的 <i>requires</i> 子句、按出现顺序的每个函数参数的制约、尾随的 <i>requires</i> 子句:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 声明用制约 Incrementable<T> && Decrementable<T> 声明同一有制约函数模板 </span>
|
|
<span class="kw1">template</span><span class="sy1"><</span>Incrementable T<span class="sy1">></span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span> requires Decrementable<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
requires Incrementable<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> Decrementable<span class="sy1"><</span>T<span class="sy1">></span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
|
|
<span class="co1">// 下列二个声明拥有不同制约:</span>
|
|
<span class="co1">// 第一个声明有 Incrementable<T> && Decrementable<T></span>
|
|
<span class="co1">// 第二个声明有 Decrementable<T> && Incrementable<T></span>
|
|
<span class="co1">// 尽管它们逻辑等价。</span>
|
|
<span class="co1">// 第二个声明为病式,不要求诊断。</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span>Incrementable T<span class="sy1">></span> requires Decrementable<span class="sy1"><</span>T<span class="sy1">></span> <span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span>Decrementable T<span class="sy1">></span> requires Incrementable<span class="sy1"><</span>T<span class="sy1">></span> <span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E5.90.88.E5.8F.96">合取</span></h4>
|
|
<p>以 <span class="t-c"><span class="mw-geshi cpp source-cpp">P <span class="sy3">&&</span> Q</span></span> 指定制约 <code>P</code> 与 <code>Q</code> 的合取。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 来自标准库(范围 TS)的示例概念</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Integral <span class="sy1">=</span> <a href="cpp-types-is_integral.html"><span class="kw456">std::<span class="me2">is_integral</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">::</span><span class="me2">value</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> SignedIntegral <span class="sy1">=</span> Integral<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> <a href="cpp-types-is_signed.html"><span class="kw516">std::<span class="me2">is_signed</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">::</span><span class="me2">value</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> UnsignedIntegral <span class="sy1">=</span> Integral<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> <span class="sy3">!</span>SignedIntegral<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>二个制约的合取,仅若二个制约均得到满足才得到满足。合取从左到右且为短路求值(若不满足左侧制约,则不尝试对右侧制约的模板实参替换:这阻止立即语境之外替换导致的失败)。制约合取中不允许用户定义的 <code>operator&&</code> 重载。</p>
|
|
<h4><span class="mw-headline" id=".E6.9E.90.E5.8F.96">析取</span></h4>
|
|
<p>以 <span class="t-c"><span class="mw-geshi cpp source-cpp">P <span class="sy3">||</span> Q</span></span> 指定制约 <code>P</code> 与 <code>Q</code> 的析取。</p>
|
|
<p>若任一制约得到满足,则二个制约的析取的到满足。析取从左到右且为短路求值(若满足左侧制约,则不尝试对右侧制约的模板实参替换)。制约析取中不允许用户定义的 <code>operator||</code> 重载。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 来自标准库(范围 TS )的示例制约</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T <span class="sy1">=</span> <span class="kw4">void</span><span class="sy1">></span>
|
|
requires EqualityComparable<span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span> <span class="sy3">||</span> Same<span class="sy1"><</span>T, <span class="kw4">void</span><span class="sy1">></span>
|
|
<span class="kw1">struct</span> equal_to<span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E8.B0.93.E8.AF.8D.E5.88.B6.E7.BA.A6">谓词制约</span></h4>
|
|
<p>谓词制约是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> 类型的常量表达式。它仅若求值为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw2">true</span></span></span> 才得到满足。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> Size32 <span class="sy1">=</span> sizeof<span class="br0">(</span>T<span class="br0">)</span> <span class="sy1">==</span> <span class="nu0">4</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>谓词制约能指定非类型模板形参上和模板模板实参上的要求。</p>
|
|
<p>谓词制约必须直接求值为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> ,不允许转换:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> <span class="kw1">struct</span> S <span class="br0">{</span>
|
|
<span class="kw4">constexpr</span> <span class="kw1">explicit</span> operator <span class="kw4">bool</span><span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
requires S<span class="sy1"><</span>T<span class="sy1">></span><span class="br0">{</span><span class="br0">}</span> <span class="co1">// 坏的谓词制约: S<T>{} 不是 bool</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:决不满足制约</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E8.A6.81.E6.B1.82">要求</span></h3>
|
|
<p>关键词 <span class="t-c"><span class="mw-geshi cpp source-cpp">requires</span></span> 有二种使用方式:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 引入 <i>requires 子句</i>,它指定模板实参或函数声明上的制约。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy3">&&</span><span class="br0">)</span> requires Eq<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 能作为函数声明器的最末元素出现</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> requires Addable<span class="sy1"><</span>T<span class="sy1">></span> <span class="co1">// 或在模板形参列表之右</span>
|
|
T add<span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a <span class="sy2">+</span> b<span class="sy4">;</span> <span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li"></span> 此情况下,关键词 <i>requires</i> 必须为某个常量表达式所后随(故可以写 "requires true;" ),但其意图是使用具名概念(如上述示例中)或具名概念的合取/析取或 <i>requires 表达式</i>。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 开始 <i>requires 表达式</i>,它是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> 类型纯右值,描述某些模板实参上的制约。若满足对应概念则这种表达式为 <code>true</code> ,否则为 false :
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Addable <span class="sy1">=</span> requires <span class="br0">(</span>T x<span class="br0">)</span> <span class="br0">{</span> x <span class="sy2">+</span> x<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// requires 表达式</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> requires Addable<span class="sy1"><</span>T<span class="sy1">></span> <span class="co1">// requires 子句,非 requires 表达式</span>
|
|
T add<span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a <span class="sy2">+</span> b<span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
requires requires <span class="br0">(</span>T x<span class="br0">)</span> <span class="br0">{</span> x <span class="sy2">+</span> x<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 随即制约,注意使用二次关键字</span>
|
|
T add<span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a <span class="sy2">+</span> b<span class="sy4">;</span> <span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p><i>requires 表达式</i>的语法如下:</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><code><b>requires</b></code> <code><b>(</b></code> <span class="t-spar">parameter-list</span><span class="t-mark">(可选)</span> <code><b>)</b></code> <code><b>{</b></code> <span class="t-spar">requirement-seq</span> <code><b>}</b></code></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">parameter-list</span></td>
|
|
<td>-</td>
|
|
<td>逗号分隔列表,如在函数声明中,除了不允许默认参数,且最后的参数不能是省略号。这些参数无存储期、链接或生存期。这些参数在 <span class="t-spar">requirement-seq</span> 的闭 <code><b>}</b></code> 前处于作用域中。若不使用参数,则环绕的括号亦可省略</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">requirement-seq</span></td>
|
|
<td>-</td>
|
|
<td><i>要求</i>的空白符分隔序列,描述于下(每个要求以分号结尾)。每个要求添加另一制约到此 requires 表达式所定义的制约<i>合取</i>。</td>
|
|
</tr>
|
|
</table>
|
|
<p><span class="t-spar">requirements-seq</span> 中的每个要求是下列之一:</p>
|
|
<ul>
|
|
<li>简单要求</li>
|
|
<li>类型要求</li>
|
|
<li>复合要求</li>
|
|
<li>嵌套要求</li>
|
|
</ul>
|
|
<p>要求可以提及在作用域中的模板形参,和于 <span class="t-spar">parameter-list</span> 引入的局部参数。在参数化时,称 requires 表达式引入一个<i>参数化制约</i>。</p>
|
|
<p>替换模板实参到至 reqiures 表达式可能导致于其要求中形成非法类型或表达式。这些情况下,</p>
|
|
<ul>
|
|
<li>若替换失败出现于用于<a href="cpp-language-templates.html#.E6.A8.A1.E6.9D.BF.E5.8C.96.E5.AE.9E.E4.BD.93">模板化实体</a>声明之外的 requires 表达式,则程序为病式。</li>
|
|
<li>若 requires 表达式用于<a href="cpp-language-templates.html#.E6.A8.A1.E6.9D.BF.E5.8C.96.E5.AE.9E.E4.BD.93">模板化实体</a>的声明中,则对应的制约被当做“不满足”而<a href="cpp-language-sfinae.html">替换失败不是错误</a>,然而</li>
|
|
<li>若替换失败会在对每个可能模板实参的 requires 表达式中出现,则程序为病式,不要求诊断:</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C <span class="sy1">=</span> requires <span class="br0">{</span>
|
|
new <span class="kw4">int</span><span class="br0">[</span><span class="sy2">-</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span>sizeof<span class="br0">(</span>T<span class="br0">)</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 对每个 T 非法:病式,不要求诊断</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E7.AE.80.E5.8D.95.E8.A6.81.E6.B1.82">简单要求</span></h4>
|
|
<p>简单要求是任意表达式语句。要求是表达式合法(是为<i>表达式制约</i>)。不同于谓词制约,不发生求值,只检查语言正确性。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Addable <span class="sy1">=</span>
|
|
requires <span class="br0">(</span>T a, T b<span class="br0">)</span> <span class="br0">{</span>
|
|
a <span class="sy2">+</span> b<span class="sy4">;</span> <span class="co1">// “表达式 a + b 是可编译的合法表达式”</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 来自标准库(范围 TS )的示例</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">class</span> U <span class="sy1">=</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Swappable <span class="sy1">=</span> requires<span class="br0">(</span>T<span class="sy3">&&</span> t, U<span class="sy3">&&</span> u<span class="br0">)</span> <span class="br0">{</span>
|
|
swap<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span>t<span class="br0">)</span>, <a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>U<span class="sy1">></span><span class="br0">(</span>u<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
swap<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>U<span class="sy1">></span><span class="br0">(</span>u<span class="br0">)</span>, <a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span>t<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E7.B1.BB.E5.9E.8B.E8.A6.81.E6.B1.82">类型要求</span></h4>
|
|
<p>类型要求是关键词 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">typename</span></span></span> 后随类型名,可选地有限定。要求是该具名类型存在(<i>类型制约</i>):这可用于校验具体的具名嵌套类型是否存在,或类模板特化是否指名一个类型,或别名模板是否指名一个类型。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> <span class="kw1">using</span> Ref <span class="sy1">=</span> T<span class="sy3">&</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C <span class="sy1">=</span>
|
|
requires <span class="br0">{</span>
|
|
<span class="kw1">typename</span> T<span class="sy4">::</span><span class="me2">inner</span><span class="sy4">;</span> <span class="co1">// 要求的嵌套成员名</span>
|
|
<span class="kw1">typename</span> S<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 要求的类模板特化</span>
|
|
<span class="kw1">typename</span> Ref<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 要求的别名模版替换</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 来自标准库(范围 TS )的示例概念</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">></span> <span class="kw1">using</span> CommonType <span class="sy1">=</span> <a href="cpp-types-common_type.html"><span class="kw636">std::<span class="me2">common_type_t</span></span></a><span class="sy1"><</span>T, U<span class="sy1">></span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> Common <span class="sy1">=</span>
|
|
requires <span class="br0">(</span>T t, U u<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">typename</span> CommonType<span class="sy1"><</span>T, U<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// CommonType<T, U> 合法且指名类型</span>
|
|
<span class="br0">{</span> CommonType<span class="sy1"><</span>T, U<span class="sy1">></span><span class="br0">{</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span>t<span class="br0">)</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">{</span> CommonType<span class="sy1"><</span>T, U<span class="sy1">></span><span class="br0">{</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>U<span class="sy1">></span><span class="br0">(</span>u<span class="br0">)</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E5.A4.8D.E5.90.88.E8.A6.81.E6.B1.82">复合要求</span></h4>
|
|
<p>复合要求拥有形式</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><code><b>{</b></code> <span class="t-spar">expression</span> <code><b>}</b></code> <code><b>noexcept</b></code><span class="t-mark">(可选)</span> <span class="t-spar">trailing-return-type</span><span class="t-mark">(可选)</span> <code><b>;</b></code></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>并指定下列制约的合取:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> <span class="t-spar">expression</span> 是合法表达式(<i>表达式制约</i>)</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 若使用 <code>noexcept</code> ,则表达式必须亦为 noexcept (<i>异常制约</i>)</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 若 <span class="t-spar">trailing-return-type</span> 指名用占位符的类型,则类型必须可从表达式的类型推导(<i>实参推导制约</i>)</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 若 <span class="t-spar">trailing-return-type</span> 指名不用占位符的类型,则再添加二个制约:</div>
|
|
<div class="t-li2"><span class="t-li">4a)</span> <span class="t-spar">trailing-return-type</span> 所指名的类型合法(<i>类型制约</i>)</div>
|
|
<div class="t-li2"><span class="t-li">4b)</span> 表达式结果<a href="cpp-language-implicit_conversion.html">可隐式转换</a>成该类型(<i>隐式转换制约</i>)</div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C2 <span class="sy1">=</span>
|
|
requires<span class="br0">(</span>T x<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="br0">{</span><span class="sy2">*</span>x<span class="br0">}</span> <span class="sy2">-</span><span class="sy1">></span> <span class="kw1">typename</span> T<span class="sy4">::</span><span class="me2">inner</span><span class="sy4">;</span> <span class="co1">// 表达式 *x 必须合法</span>
|
|
<span class="co1">// AND 类型 T::inner 必须合法</span>
|
|
<span class="co1">// AND *x 的结果必须可转换成 T::inner</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 来自标准库(范围 TS )的示例概念</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> Same <span class="sy1">=</span> <a href="cpp-types-is_same.html"><span class="kw588">std::<span class="me2">is_same</span></span></a><span class="sy1"><</span>T,U<span class="sy1">></span><span class="sy4">::</span><span class="me2">value</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> B<span class="sy1">></span> concept <span class="kw4">bool</span> Boolean <span class="sy1">=</span>
|
|
requires<span class="br0">(</span>B b1, B b2<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="br0">{</span> <span class="kw4">bool</span><span class="br0">(</span>b1<span class="br0">)</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 直接初始化制约必须使用表达式</span>
|
|
<span class="br0">{</span> <span class="sy3">!</span>b1 <span class="br0">}</span> <span class="sy2">-</span><span class="sy1">></span> <span class="kw4">bool</span><span class="sy4">;</span> <span class="co1">// 复合制约</span>
|
|
requires Same<span class="sy1"><</span>decltype<span class="br0">(</span>b1 <span class="sy3">&&</span> b2<span class="br0">)</span>, <span class="kw4">bool</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 嵌套制约,见后述</span>
|
|
requires Same<span class="sy1"><</span>decltype<span class="br0">(</span>b1 <span class="sy3">||</span> b2<span class="br0">)</span>, <span class="kw4">bool</span><span class="sy1">></span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E5.B5.8C.E5.A5.97.E8.A6.81.E6.B1.82">嵌套要求</span></h4>
|
|
<p>嵌套要求是另一以分号终止的 <i>requires 子句</i>。它被用于引入<i>谓词制约</i>(见前述),该制约以另一应用到局部参数的具名制约表达(在 requires 子句外,谓词制约不能使用参数,而直接放置表达式于 requires 子句中会令它成为表达式制约,这表示不求值它)。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 来自范围 TS 的示例制约</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> Semiregular <span class="sy1">=</span> DefaultConstructible<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span>
|
|
CopyConstructible<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> Destructible<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> CopyAssignable<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span>
|
|
requires<span class="br0">(</span>T a, size_t n<span class="br0">)</span> <span class="br0">{</span>
|
|
requires Same<span class="sy1"><</span>T<span class="sy2">*</span>, decltype<span class="br0">(</span><span class="sy3">&</span>a<span class="br0">)</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 嵌套:“ Same<...> 求值为 true ”</span>
|
|
<span class="br0">{</span> a.~T<span class="br0">(</span><span class="br0">)</span> <span class="br0">}</span> <span class="kw1">noexcept</span><span class="sy4">;</span> <span class="co1">// 复合: "a.~T()" 是不抛出的合法表达式</span>
|
|
requires Same<span class="sy1"><</span>T<span class="sy2">*</span>, decltype<span class="br0">(</span>new T<span class="br0">)</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 嵌套:“ Same<...> 求值为 true ”</span>
|
|
requires Same<span class="sy1"><</span>T<span class="sy2">*</span>, decltype<span class="br0">(</span>new T<span class="br0">[</span>n<span class="br0">]</span><span class="br0">)</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// 嵌套</span>
|
|
<span class="br0">{</span> delete new T <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 复合</span>
|
|
<span class="br0">{</span> delete new T<span class="br0">[</span>n<span class="br0">]</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 复合</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.A6.82.E5.BF.B5.E5.86.B3.E8.AE.AE">概念决议</span></h3>
|
|
<p>类似任何其他函数模板,函数概念(但不是变量概念)能重载:可以提供全部使用同一 <span class="t-spar">concept-name</span> 的多个概念定义。</p>
|
|
<p>概念决议在 <span class="t-spar">concept-name</span> (可以有限定)出现于下列语境时进行</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 有制约类型指定符 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span> f<span class="br0">(</span>Concept<span class="br0">)</span><span class="sy4">;</span> <a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span>Concept<span class="sy1">></span> x <span class="sy1">=</span> ...<span class="sy4">;</span></span></span></div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 有制约形参 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span>Concept T<span class="sy1">></span> <span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></span></span></div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 模板引入 <span class="t-c"><span class="mw-geshi cpp source-cpp">Concept<span class="br0">{</span>T<span class="br0">}</span> <span class="kw1">struct</span> X<span class="sy4">;</span></span></span></div>
|
|
<div class="t-li1"><span class="t-li">4)</span> <i>制约表达式</i> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> <span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span> requires Concept<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span></span></span></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T, <span class="kw1">typename</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> C<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>C<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// C 所指代的制约集包含 #1 和 #2 ;</span>
|
|
<span class="co1">// 概念决议(见后述)选择 #1 。</span></pre></div>
|
|
</div>
|
|
<p>为进行概念决议,每个匹配名称(与限定,若存在)的<i>模板形参</i>都与模板实参与<i>通配符</i>这些<i>概念实参</i>的序列配对。通配符可匹配任何种类(类型、非类型、模板)的模板实参。形参集构造方式各异,依赖于语境</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 对于用作有制约类型指定符或形参一部分的概念名,若概念名以无形参列表使用,则实参列表是单个通配符。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T, <span class="kw1">typename</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> C1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> f1<span class="br0">(</span><span class="kw4">const</span> C1<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// <wildcard> 匹配 <T> ,选择 #1</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 对于用作有制约类型指定符或形参一部分的概念名,若概念名以模板实参列表使用,则实参列表是一个通配符后随实参列表。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T, <span class="kw1">typename</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> C1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> f2<span class="br0">(</span>C1<span class="sy1"><</span><span class="kw4">char</span><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// <wildcard, char> 匹配 <T, U> ,选择 #2</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 若概念出现于模板引入中,则实参列表是与模板引入中形参列表等长的占位符序列
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span>... <span class="me1">Ts</span><span class="sy1">></span>
|
|
concept <span class="kw4">bool</span> C3 <span class="sy1">=</span> <span class="kw2">true</span><span class="sy4">;</span>
|
|
C3<span class="br0">{</span>T<span class="br0">}</span> <span class="kw4">void</span> q2<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK: <T> 匹配 <...Ts></span>
|
|
C3<span class="br0">{</span>...<span class="me1">Ts</span><span class="br0">}</span> <span class="kw4">void</span> q1<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK: <...Ts> 匹配 <...Ts></span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 若概念作为模板 id 出现,则概念实参列表准确地是该模板 id 的实参序列
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T, <span class="kw1">typename</span> U<span class="sy1">></span> concept <span class="kw4">bool</span> C<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// #2</span>
|
|
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span> requires C<span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 匹配 #1</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>概念决议通过配对每个实参和对应每个可见概念的对应形参进行。默认模板实参(若使用)为每个不对应实参的形参实例化,然后后附到实参列表。模板实参匹配形参,仅若它拥有相同种类(类型、非类型、模板),除非实参是通配符。形参包可匹配零或更多实参,只要所有实参都匹配种类中的模式(除非它们是通配符)。</p>
|
|
<p>若任何实参不匹配其对应的形参,或若有多于形参的实参,且最后的形参不是包,则该概念不可达。若有零或多于一个可生成概念,则程序为病式。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw4">int</span> T<span class="sy1">></span> concept <span class="kw4">bool</span> C2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="kw2">true</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span>C2<span class="sy1"><</span><span class="nu0">0</span><span class="sy1">></span> T<span class="sy1">></span> <span class="kw1">struct</span> S1<span class="sy4">;</span> <span class="co1">// 错误: <wildcard, 0> 不匹配 <typename T> 或 <int T></span>
|
|
<span class="kw1">template</span><span class="sy1"><</span>C2 T<span class="sy1">></span> <span class="kw1">struct</span> S2<span class="sy4">;</span> <span class="co1">// #1 与 #2 均匹配:错误</span></pre></div>
|
|
</div>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:需要一个带有意义概念的示例,而非这些 'return true' 占位符</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.88.B6.E7.BA.A6.E7.9A.84.E5.81.8F.E5.BA.8F">制约的偏序</span></h3>
|
|
<p>在任何进一步分析前,通过替换每个具名概念和每个 requires 表达式的体<i>规范化</i>制约,直到剩下原子制约上的合取与析取序列。原子制约是谓词制约、表达式制约、隐式转换制约、实参推导制约和异常制约。</p>
|
|
<p>若能不因等价性分析类型和表达式就能证明概念 <code>P</code> <a href="https://en.wikipedia.org/wiki/Logical_consequence" class="extiw" title="enwiki:Logical consequence">蕴含</a> 概念 <code>Q</code> ,则说 <code>P</code> <i>包含</i> <code>Q</code> (故 <code>N >= 0</code> 不包含 <code>N > 0</code> )</p>
|
|
<p>具体而言,转换首个 <code>P</code> 为析取范式并转换 <code>Q</code> 为合取范式,再以下列方式比较它们:</p>
|
|
<ul>
|
|
<li>每个原子制约 <code>A</code> 包含等价的原子制约 <code>A</code></li>
|
|
<li>每个原子制约 <code>A</code> 包含析取 <code>A||B</code> 而不包含合取 <code>A&&B</code></li>
|
|
<li>每个合取 <code>A&&B</code> 包含 <code>A</code> ,但析取 <code>A||B</code> 不包含 <code>A</code></li>
|
|
</ul>
|
|
<p>包含关系定义制约上的偏序,这被用于确定:</p>
|
|
<ul>
|
|
<li><a href="cpp-language-overload_resolution.html">重载决议</a>中非模板函数的最佳可生成候选</li>
|
|
<li>重载集中<a href="cpp-language-overloaded_address.html">非模板函数的地址</a></li>
|
|
<li>模板模板实参的最佳匹配</li>
|
|
<li>类模板特化的偏序</li>
|
|
<li>函数模板的<a href="cpp-language-function_template.html#.E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E9.87.8D.E8.BD.BD">偏序</a></li>
|
|
</ul>
|
|
<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>若声明 <code>D1</code> 与 <code>D2</code> 有制约且 D1 的规范化制约包含 D2 的规范化制约(或若 D1 有制约而 D2 无制约),则说 D1 与 D2 相比<i>至少一样有制约</i>。若 D1 至少与 D2 一样有制约,而 D2 不至少与 D1 一样有制约,则 D1 比 D2 <i>更受制约</i>。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept Decrementable <span class="sy1">=</span> requires<span class="br0">(</span>T t<span class="br0">)</span> <span class="br0">{</span> <span class="sy2">--</span>t<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
concept RevIterator <span class="sy1">=</span> Decrementable<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy3">&&</span> requires<span class="br0">(</span>T t<span class="br0">)</span> <span class="br0">{</span> <span class="sy2">*</span>t<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// RevIterator 包含 Decrementable ,但非相反</span>
|
|
<span class="co1">// RevIterator 比 Decrementable 更受制约</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span>Decrementable<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>RevIterator<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
|
|
|
|
f<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// int 仅满足可自增,选择 #1</span>
|
|
f<span class="br0">(</span><span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// int* 满足二个制约,选择 #2 ,因为更受制约</span>
|
|
|
|
<span class="kw4">void</span> g<span class="br0">(</span><span class="kw4">auto</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3(无制约)</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span>Decrementable<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #4</span>
|
|
|
|
g<span class="br0">(</span><span class="kw2">true</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// bool 不满足 Decrementable ,选择 #3</span>
|
|
g<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// int 满足 Decrementable ,选择 #4 因为它更受制约</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="cpp-keyword-concept.html"><tt>concept</tt></a>, <a href="cpp-keyword-requires.html"><tt>requires</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E7.BC.96.E8.AF.91.E5.99.A8.E6.94.AF.E6.8C.81">编译器支持</span></h3>
|
|
<p>GCC >= 6.1 支持此技术规范(要求选项 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">-</span>fconcepts</span></span> )。</p>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|