查验C++类型推导结果 | Check C++ Type Deduction Result
<h2 id="如何查看类型">如何查看类型</h2>
<p>C++的类型系统是极其复杂的,基本类型与const, volatile, 指针,引用,数组,函数,类,成员变量,
成员函数等特性的组合能生成许多不同的类型。类型推导是C++泛型编程/模版元编程的基础。
那么如何查看某个类型或变量具体是什么类型呢?我使用的方法有</p>
<ul>
<li>C++内置的typeid</li>
<li>boost::typeindex::type_id</li>
<li>猜测类型并用std::is_same校验</li>
<li>故意使编译报错在编译器给出的错误信息中查看目标的类型</li>
</ul>
<p>例如用typeid:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="k">typeid</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">)).</span><span class="n">name</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints: A3_i
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见使用typeid获取的类型名不具有好的可读性。于是可以用boost::typeindex::type_id替代:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// need include this header
</span></span></span><span class="line"><span class="cl"><span class="c1">// #include <boost/type_index.hpp>
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">boost</span><span class="o">::</span><span class="n">typeindex</span><span class="o">::</span><span class="n">type_id</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="o">></span><span class="p">().</span><span class="n">pretty_name</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// prints: int [3]
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见虽然结果具有很好的可读性,但是却去掉了const属性,与真实输入类型不符合。</p>
<p>事实上,C++内置的typeid和Boost的type_id得出的结果都是对输入类型去掉了
const, volatile和引用属性的。</p>
<p>那有没有获取完整类型的方法呢?
C++中可以用std::is_same来判断两个类型是否相同,它没有对输入类型做任何改变。
因此可以猜测一个结果然后用它来判断猜得是否正确:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same_v</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> <span class="kt">int</span> <span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">></span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// a has type: int [3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same_v</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> <span class="k">const</span> <span class="kt">int</span> <span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">></span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// a has type: const int [3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>但是这样太麻烦了,如果不想猜呢?由于编译器编译阶段是知道变量或表达式的类型的,所以我们可以故意
写某种会编译报错的代码,让我们想要查看的类型名展示在报错信息中:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span><span class="o">></span> <span class="k">struct</span> <span class="nc">EMPTY</span><span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="c1">// CE: compilation error; NX: not exists
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#define CETYPE(type) EMPTY<type>::NX()
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>编译报错信息是:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">error: no member named 'NX' in 'EMPTY<const int[3]>'
</span></span></code></pre></td></tr></table>
</div>
</div><p>于是可以看出a的类型是"const int[3]"。
(也有编译器输出"int const[3]",这是等效的写法,它们是相同的类型)</p>
<h2 id="类型推导示例">类型推导示例</h2>
<h3 id="c-function">C function</h3>
<p>预先定义好的用于类型推导的函数:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">func</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="p">{}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">func</span><span class="p">));</span> <span class="c1">// void (int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">func</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// implicitly convert to pointer if assigned by function name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">fcopy</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">fcopy</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="n">cfcopy</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">cfcopy</span><span class="p">));</span> <span class="c1">// void (*const)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// same as above
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">fptr</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">fptr</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="n">cfptr</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">cfptr</span><span class="p">));</span> <span class="c1">// void (*const)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// static_cast on rvalue reference to function returns lvalue
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="k">static_cast</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="o">&&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">func</span><span class="p">)));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="k">static_cast</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">func</span><span class="p">)));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// so, std::move on function returns lvalue reference
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">)));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">)));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="o">&</span><span class="n">func</span><span class="p">)));</span> <span class="c1">// void (*&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// explicitly define a rvalue reference to function
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">decltype</span><span class="p">(</span><span class="n">func</span><span class="p">)</span> <span class="o">&&</span> <span class="n">prfunc</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">prfunc</span><span class="p">));</span> <span class="c1">// void (&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// again, std::move on rvalue reference to function also returns lvalue reference
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">prfunc</span><span class="p">)));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// references
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&</span> <span class="n">lref</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">lref</span><span class="p">));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">lref</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 由于规定非成员函数不能有const属性,所以const被忽略掉
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&&</span> <span class="n">rref</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">rref</span><span class="p">));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">rref</span><span class="p">));</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// ref of move
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref_of_move</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref_of_move</span><span class="p">));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="o">&&</span> <span class="n">rref_of_move</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">rref_of_move</span><span class="p">));</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// references of pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// &func is a rvalue pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="o">&&</span> <span class="n">rref</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">rref</span><span class="p">));</span> <span class="c1">// void (*&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// pfunc is a lvalue pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">pfunc</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref</span> <span class="o">=</span> <span class="n">pfunc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="o">&&</span> <span class="n">rref</span> <span class="o">=</span> <span class="n">pfunc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">rref</span><span class="p">));</span> <span class="c1">// void (*&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// ref of move
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref_of_move</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">pfunc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref_of_move</span><span class="p">));</span> <span class="c1">// void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="o">&&</span> <span class="n">rref_of_move</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">pfunc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">rref_of_move</span><span class="p">));</span> <span class="c1">// void (*&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>定义如下两个模版函数,其参数声明分别是C++11以前的万能引用和C++11引入的新的万能引用。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span> <span class="kt">void</span> <span class="n">larg</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span> <span class="o">&</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">t</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span> <span class="kt">void</span> <span class="n">rarg</span><span class="p">(</span><span class="n">T</span> <span class="o">&&</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">t</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>将函数func用作以上两个模版函数的参数,类型推导结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">larg</span><span class="p">(</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">rarg</span><span class="p">(</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">larg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">rarg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">func</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">larg</span><span class="p">(</span><span class="o">&</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">rarg</span><span class="p">(</span><span class="o">&</span><span class="n">func</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">pfunc</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">larg</span><span class="p">(</span><span class="n">pfunc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">rarg</span><span class="p">(</span><span class="n">pfunc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">pfunc</span> <span class="o">=</span> <span class="o">&</span><span class="n">func</span><span class="p">;</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">larg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">pfunc</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*const &)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="n">rarg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">pfunc</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(T); // void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// CETYPE(decltype(t)); // void (*&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="小结">小结</h4>
<p>可见,函数模版参数<code>const T & t</code>与定义引用<code>const auto & r = ...</code>推导结果一致,
函数模版参数<code>T && t</code>与定义引用<code>auto && r = ...</code>推导结果一致。</p>
<p>特别的,<strong>std::move 或 std::forward 作用于函数类型时返回的总是 lvalue <code>FunctionType&</code> 而不是<code>FunctionType&&</code></strong>。
这是因为 <code>static_cast<FunctionType&&>(func)</code> 返回的是 <code>FunctionType&</code> 而不是 <code>FunctionType&&</code>。</p>
<p>另外,由于C++规定不是成员函数的函数不能有const、valitale属性,所以
<code>const auto & clref = func;</code>得到clref的类型是<code>void (&)(int)</code>,const属性被忽略了。
如果换成其他类型,则const属性会被保留,例如int,如下:</p>
<h3 id="int">Int</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// const被保留
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">clref</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// const int &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">clref</span><span class="p">));</span> <span class="c1">// const int *
</span></span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">ci</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">i</span><span class="p">));</span> <span class="c1">// int
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">ci</span><span class="p">));</span> <span class="c1">// const int
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 非单个标记符的左值,推导为T&。例如加一个小括号,或前置自增
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">((</span><span class="n">i</span><span class="p">)));</span> <span class="c1">// int &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">((</span><span class="n">ci</span><span class="p">)));</span> <span class="c1">// const int &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">++</span><span class="n">i</span><span class="p">));</span> <span class="c1">// int &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 后置自增是一个右值,于是推导为T
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">i</span><span class="o">++</span><span class="p">));</span> <span class="c1">// int
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 右值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="n">ci</span><span class="p">));</span> <span class="c1">// int
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 右值引用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">i</span><span class="p">)));</span> <span class="c1">// int &&
</span></span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">larg</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // int
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // const int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">rarg</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">larg</span><span class="p">(</span><span class="n">ci</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // int
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // const int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">rarg</span><span class="p">(</span><span class="n">ci</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // const int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // const int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">larg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">i</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void larg(const T & t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // int
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // const int &
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">rarg</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">ci</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // const int
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // const int &&
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">rarg</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// template<typename T> void rarg(T && t) {
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(T); // int
</span></span></span><span class="line"><span class="cl"><span class="c1">// CETYPE(decltype(t)); // int &&
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="c-array">C array</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">));</span> <span class="c1">// char[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">));</span> <span class="c1">// char (*)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span> <span class="c1">// char *
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">acr</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">acr</span><span class="p">));</span> <span class="c1">// const char (&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">pacr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pacr</span><span class="p">));</span> <span class="c1">// char (*const &)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">pa0cr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pa0cr</span><span class="p">));</span> <span class="c1">// char *const &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">arr</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">arr</span><span class="p">));</span> <span class="c1">// char (&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="o">&&</span> <span class="n">parr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">parr</span><span class="p">));</span> <span class="c1">// char (*&&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">pa</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">lparr</span> <span class="o">=</span> <span class="n">pa</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">lparr</span><span class="p">));</span> <span class="c1">// char (*&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">pa0rr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pa0rr</span><span class="p">));</span> <span class="c1">// char *&&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">pa0</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">lpa0rr</span> <span class="o">=</span> <span class="n">pa0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">lpa0rr</span><span class="p">));</span> <span class="c1">// char *&
</span></span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">char</span> <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">a</span><span class="p">));</span> <span class="c1">// const char[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">));</span> <span class="c1">// const char (*)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span> <span class="c1">// const char *
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">acr</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">acr</span><span class="p">));</span> <span class="c1">// const char (&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">pacr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pacr</span><span class="p">));</span> <span class="c1">// const char (*const &)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">pa0cr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pa0cr</span><span class="p">));</span> <span class="c1">// const char *const &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">arr</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">arr</span><span class="p">));</span> <span class="c1">// const char (&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="o">&&</span> <span class="n">parr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">parr</span><span class="p">));</span> <span class="c1">// const char (*&&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">pa</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">lparr</span> <span class="o">=</span> <span class="n">pa</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">lparr</span><span class="p">));</span> <span class="c1">// const char (*&)[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">pa0rr</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">pa0rr</span><span class="p">));</span> <span class="c1">// const char *&&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">pa0</span> <span class="o">=</span> <span class="o">&</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="o">&&</span> <span class="n">lpa0rr</span> <span class="o">=</span> <span class="n">pa0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">lpa0rr</span><span class="p">));</span> <span class="c1">// const char *&
</span></span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">ia</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">ia2</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">ia3</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">ia</span><span class="p">));</span> <span class="c1">// int[0]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">ia2</span><span class="p">));</span> <span class="c1">// int[2]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">ia3</span><span class="p">));</span> <span class="c1">// int[3]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="kt">int</span><span class="p">[]);</span> <span class="c1">// int[]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">const</span> <span class="kt">int</span><span class="p">[]);</span> <span class="c1">// const int[]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">ia</span><span class="p">));</span> <span class="c1">// int (*)[0]
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="c-string">C string</h3>
<p>字面字符串常量,decltype推断结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="s">"abcd"</span><span class="p">));</span> <span class="c1">// const char (&)[5]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">s</span> <span class="o">=</span> <span class="s">"abcd"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">s</span><span class="p">));</span> <span class="c1">// const char *
</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="c中的函数类型到底有多少种形式">C++中的函数类型到底有多少种形式?</h2>
<p>影响函数类型的修饰属性都是正交的,因此把每一种属性的选项数量乘起来就是答案。
根据一个函数类型是否是const的,是否是volatile的,是否有C语言风格的可变长实参,
是没有成员函数引用属性还是具有成员函数左值引用或成员函数右值引用
(<strong>请注意,这里一定是成员函数引用才算作函数类型签名,C语言函数的引用在此不算作函数类型</strong>),
还有C++17以后一个函数是否是noexcept也认作不同的函数类型,
所以根据这五种属性可以算出总共是<code>2 * 2 * 2 * 3 * 2 = 48</code>种!</p>
<p>判断一个类型是否是函数类型,C++标准库中定义了<code>std::is_function</code>来实现这个判断。
它的一种可能的实现方式就是把以上所说所有的函数类型形式都特化一遍,如下所示:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// primary template
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o"><</span><span class="k">typename</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">false_type</span> <span class="p">{</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// specialization for regular functions
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// specialization for variadic functions such as std::printf
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// specialization for function types that have cv-qualifiers
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// specialization for function types that have ref-qualifiers
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&&></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// specializations for noexcept versions of all the above (C++17 and later)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">volatile</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">volatile</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>针对上文特别提起的<strong>引用属性</strong>举个例子:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// 这两个是C语言函数的引用,判断为false
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">is_function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">is_function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="o">&&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 而这两个是成员函数的引用,判断为true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">is_function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&>::</span><span class="n">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">is_function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&&>::</span><span class="n">value</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="对函数类型进行add-pointercvr-remove-cvr等操作是什么结果">对函数类型进行add pointer/c/v/r, remove c/v/r等操作是什么结果?</h2>
<p>以上48种函数类型形式其实可分成两类。</p>
<p>第一类是<strong>C语言函数形式</strong>的函数类型,上文也提到,C++规定它们不允许有const和volatile属性,
当然它不是成员函数自然也不能有成员函数引用属性,只能有可变长实参属性和noexcept属性;</p>
<p>剩下的就是第二类,<strong>非C语言函数形式</strong>的函数类型,凡是具有const属性、volatile属性、
成员函数引用属性 的都属于这类,这一类更像是成员函数,但是不具有母类类型信息,不是完整的成员函数类型,
姑且叫<strong>成员函数形式</strong>的函数类型或者<strong>不完整成员函数类型</strong>吧。</p>
<p>用cppreference的说法,也可以说成第一类是"<strong>not cv- or ref- qualified</strong> function type",
第二类是"<strong>cv- or ref- qualified</strong> function type".
不过也许说成C语言函数形式和成员函数形式,理解它们一个是完整的,一个是不完整的,
可能能更好得理解它们为什么会有以下令人费解令人诧异的不同表现。</p>
<p>算一下,第一类有4种,第二类有44种。</p>
<h3 id="add-reference-and-remove-reference">add reference and remove reference</h3>
<p>针对C语言函数形式的函数类型添加引用结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int, ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&&)(int, ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&&)(int) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int, ...) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&&)(int, ...) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 引用折叠
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (&&)(int)
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见这些函数类型都被添加了引用,不过应该注意这个是常规引用(某种类型整体的引用),
不是成员函数引用,这个引用<strong>不影响函数签名</strong>。
顺便提一下,对以上输出的带引用的类型施加std::remove_reference_t当然也会回到原输入类型。</p>
<p>针对成员函数形式的函数类型add和remove引用结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// add reference
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) volatile
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="k">volatile</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...) volatile
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="k">const</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...) const
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) volatile noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) &&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) &&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) const &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_rvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) volatile &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_lvalue_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const && noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// remove reference
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) &&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) const &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) const &&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int) volatile &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) & noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const & noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_reference_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) volatile && noexcept
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见无论是add还是remove reference,对输入的函数类型,都没有做任何更改。所以可得:</p>
<ul>
<li>C语言函数形式的函数类型可以添加引用,而成员函数形式的函数类型本身自带的引用属性不会被更改。</li>
</ul>
<p>成员函数的引用,在这里由于<strong>成为了函数签名的一部分,属于函数类型的一部分</strong>,所以这时的引用就与普通常规引用大不相同,
比普通引用的地位更高一等,是不能通过std::add_lvalue_reference, std::remove_reference等被改变的。</p>
<p>那么这类引用就太特殊了,凭什么都是函数类型,一些能被添加引用和去除引用,而另一种不能呢?
是否应该把它定义为另外一类引用,或者另外起一个名字称为另外一类功能?
然后与常规引用不冲突,再可以添加常规引用呢?那么可能就会出现形如<code>void (&)(int) const &&</code>
之类的东西了。😂复杂程度又增加了,不过好像又能够和第一类函数类型保持一致了,是好还是不好呢?
C++的选择是不这么做,否则的话,还要再提供一种成员引用的功能与之匹配。C++现在已经有一种
成员指针的功能,即Pointer-to-member operator <code>.*</code>和<code>->*</code>,这已经够用了。
而且,从函数类型完整性上也可以理解,C语言函数形式的函数类型是完整的,可以指向某个具体的函数实体,
因此对它添加指针或引用是有意义的,而成员函数形式的函数类型是不完整的,缺乏母类信息,不能指向某个
具体的成员函数,对它添加指针或引用是没有意义的,因此C++选择没有增加不必要的复杂度。</p>
<p>如果把尾置的引用当成函数类型的一部分,不把它理解成常规引用(某种类型整体的引用),而add/remove reference针对的是常规引用,那么也可以理解为:</p>
<ul>
<li>成员函数形式的函数类型不能添加引用(常规引用)。</li>
</ul>
<h3 id="add-pointer-and-remove-pointer">add pointer and remove pointer</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// C语言函数形式,能添加指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (*)(int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (*)(int, ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (*)(int, ...) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// C语言函数指针类型,能去除指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_pointer_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_pointer_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">,...)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_pointer_t</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">,...)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 成员函数形式,不能添加指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int, ...) &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_pointer_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) volatile &&
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见:</p>
<ul>
<li>C语言函数形式的函数类型可以添加指针,而成员函数形式的函数类型不能添加指针;</li>
</ul>
<p>C语言函数形式的函数类型是完整的函数类型,但成员函数形式的函数类型是不完整的,
因为它不具有包含它的母类的类型信息,所以不难理解它不能被添加指针。</p>
<p>实际上,如果强制为其添加指针,会导致编译报错,std::add_pointer_t里面规避了这点,
对于不能添加指针的类型,返回了输入类型本身。</p>
<h3 id="add-constvolatile-remove-constvolatile">add const/volatile, remove const/volatile</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// C语言函数形式,不能添加cv
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_const_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_volatile_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_cv_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...) noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 成员函数形式,不能更改原有cv
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_const_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) & noexcept
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_volatile_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span> <span class="k">const</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int, ...) const
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">add_cv_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">&&></span><span class="p">);</span> <span class="c1">// void (int) volatile &&
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_cv_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_cv_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,...)</span> <span class="k">volatile</span> <span class="o">&></span><span class="p">);</span> <span class="c1">// void (int, ...) volatile &
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">CETYPE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">remove_cv_t</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&&</span> <span class="k">noexcept</span><span class="o">></span><span class="p">);</span> <span class="c1">// void (int) const && noexcept
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>可见:</p>
<ul>
<li>C语言函数形式的函数类型不能添加cv属性,而成员函数形式的函数类型本身自带的cv属性也不能被更改。</li>
</ul>
<p>如果把尾置的cv属性当成函数类型的一部分,而add const/volatile, remove const/volatile
指的是针对某个类型整体之外添加或去除cv属性,那么也可以理解为:</p>
<ul>
<li>成员函数形式的函数类型也不能添加cv属性。</li>
</ul>
<p>也就是,<strong>所有函数类型都不能添加cv属性</strong>。</p>
<h3 id="is_reference-is_const-is_volatile">is_reference, is_const, is_volatile</h3>
<p>对函数类型进行 std::is_const, std::is_references 判断:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 成员函数形式,这些都输出 false
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="o">&&></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_const_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_const_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">const</span> <span class="o">&></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_volatile_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">volatile</span> <span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_const_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_volatile_v</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// C语言函数形式,这些都输出 true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span> <span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">is_reference_v</span><span class="o"><</span><span class="kt">void</span> <span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span><span class="o">></span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可见当const、volatile和引用等属性成为函数签名即成为函数类型的一部分的时候,这种属性就不能用
std::is_reference, std::is_const, std::is_volatile判断出来了,结果永远是false。
而C语言函数形式的函数类型的引用不属于函数签名的一部分,可以通过std::is_reference判断出来。</p>
<h3 id="小结-1">小结</h3>
<p>由以上可得,对函数类型进行 add/remove const/volatile/reference 等操作时,
<strong>如果某种属性是属于函数签名的一部分,那么这种属性就是这个基本类型的一部分,它是不会被改变的。</strong>
而且,<strong>当某种属性属于函数签名的一部分时,是无法通过 is const/volatile/reference 等判断出是否具有这种属性的。</strong></p>
<p>可以这样理解:把函数签名整体当成一个黑盒,黑盒内部的函数签名形式上是否具有某种属性是不可见的,
也不可伸入黑盒内部对函数签名进行修改。</p>
<p>函数签名中具有<strong>尾置的const、volatile、引用</strong>的函数类型是不完整成员函数类型,不能对其添加指针和引用,否则可以。</p>
<p>所有函数类型都不能add const/volatile.</p>
<h2 id="如何判断一个类型是否是-stdfunction">如何判断一个类型是否是 std::function</h2>
<p>std::function是对函数的封装,它接受一个模板参数,该模版参数应该是一个函数类型。
经过以上讨论,我们知道函数类型有48种形式,那么是否每一种std::function都支持呢?
对于成员函数形式的函数类型我们知道它们是不完整的,对这些函数类型特化没有任何意义,那剩下的4种
C语言函数形式的函数类型 std::function是否都支持呢?事实是,目前(2023)std::function
只支持最基本的那一种,也就是只有这一种特化:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span> <span class="k">class</span> <span class="o">></span> <span class="k">class</span> <span class="nc">function</span><span class="p">;</span> <span class="cm">/* undefined */</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o"><</span> <span class="k">class</span> <span class="nc">R</span><span class="p">,</span> <span class="k">class</span><span class="err">... </span><span class="nc">Args</span> <span class="o">></span> <span class="k">class</span> <span class="nc">function</span><span class="o"><</span><span class="n">R</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span><span class="o">></span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 没有对其他形式特化
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>验证举例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span> <span class="n">f1</span><span class="p">;</span> <span class="c1">// OK!
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 这些都会编译错误:implicit instantiation of undefined template。因为标准库中并没有为其特化。
</span></span></span><span class="line"><span class="cl"><span class="c1">// std::function<void(int, ...)> f2;
</span></span></span><span class="line"><span class="cl"><span class="c1">// std::function<void(int) noexcept> f3
</span></span></span><span class="line"><span class="cl"><span class="c1">// std::function<void(int) const> f4;
</span></span></span><span class="line"><span class="cl"><span class="c1">// std::function<void(int) &> f5;
</span></span></span><span class="line"><span class="cl"><span class="c1">// std::function<void(int) &> f6;
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>上例中f2~f6会编译错误,说明std::function不支持这些函数类型。
当然如果只声明f2~f6对应的那些类型而不用它们定义变量,是不会报错的,但是这没有意义,
这只是声明了一个没有任何实现的类类型而已。</p>
<p>所以目前std::function只支持这一种最基本的函数类型形式,
<strong>要想判断一个类型是否是std::function类型,只需要对<code>Return(Args...)</code>这一种函数类型形式做一个特化即可。</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// 只需这一个primary template和一个特化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_stdfunction</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">false_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_stdfunction</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span><span class="o">>></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 以下这些特化都是不需要的,因为std::function的实现中并没有为其特化
</span></span></span><span class="line"><span class="cl"><span class="c1">// template <typename Return, typename... Args>
</span></span></span><span class="line"><span class="cl"><span class="c1">// struct is_stdfunction<std::function<Return(Args..., ...)>> : std::true_type {};
</span></span></span><span class="line"><span class="cl"><span class="c1">// template <typename Return, typename... Args>
</span></span></span><span class="line"><span class="cl"><span class="c1">// struct is_stdfunction<std::function<Return(Args...) noexcept>> : std::true_type {};
</span></span></span><span class="line"><span class="cl"><span class="c1">// template <typename Return, typename... Args>
</span></span></span><span class="line"><span class="cl"><span class="c1">// struct is_stdfunction<std::function<Return(Args..., ...) noexcept>> : std::true_type {};
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="stdfunction如何处理可变长实参variadic-functions">std::function如何处理可变长实参(variadic functions)</h3>
<p>此外,还需要说明的一个特例是可变长实参,std::function可以说是不支持这种函数类型,但也可以说是
不完全支持,或部分支持。</p>
<p>std::function的特化中虽然不支持variadic这种函数类型形式,
但是事实上我们可以将带有可变长实参的函数当成没有可变长实参的函数来用,
然后再封装在std::function里面,不过这样虽然可行,但是却丢了可变长实参部分的功能。
例如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// std::function<int(const char*, ...)> f1 = printf; // error: implicit instantiation of undefined template 'std::function<int (const char *, ...)>'
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">int</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="o">></span> <span class="n">f2</span> <span class="o">=</span> <span class="n">printf</span><span class="p">;</span> <span class="c1">// OK
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">f2</span><span class="p">(</span><span class="s">"printf no more arguments"</span><span class="p">);</span> <span class="c1">// OK
</span></span></span><span class="line"><span class="cl"><span class="c1">// f2("printf %d", 1); // error: no matching function for call to object of type 'std::function<int (const char *)>'
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>也许这也没有多大实用性,所以严格来说,std::function对带有可变长实参的函数类型还是不支持的。
那么应不应该支持一下呢?未来std::function会不会对带有variadic和noexcept的函数类型做一个特化呢?
如果他想,其实是可以的,那时候我们的is_stdfunction的后三种特化就得用上了。
不过,对noexcept的特化其实是不必要的,因为带有noexcept的函数指针,是可以转化成对应不带noexcept的函数指针的。
例如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">f1</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">f2</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_cast</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">f1</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">f2</span><span class="p">);</span> <span class="c1">// OK
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// static_cast<decltype(&f2)>(&f1); // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">p1</span> <span class="o">=</span> <span class="o">&</span><span class="n">f1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">p1</span> <span class="o">=</span> <span class="o">&</span><span class="n">f2</span><span class="p">;</span> <span class="c1">// OK
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">p2</span> <span class="o">=</span> <span class="o">&</span><span class="n">f2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// p2 = &f1; // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>例中也看到了,反过来,不带有noexcept的函数指针是不能转化成对应的带有noexcept的函数指针的。
这也可以理解,毕竟noexcept是更严格的限制,可是说是子集,而不带noexcept的是超集。</p>
<p>再有,针对可变长实参这个属性呢?
当然,有可变长实参的函数指针与对应的没有可变长实参函数指针之间是不能相互转化的,例如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">f1</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">f2</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// static_cast<decltype(&f1)>(&f2); // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// static_cast<decltype(&f2)>(&f1); // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">p1</span> <span class="o">=</span> <span class="o">&</span><span class="n">f1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// p1 = &f2; // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">p2</span> <span class="o">=</span> <span class="o">&</span><span class="n">f2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// p2 = &f1; // error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>这个std::function不对其特化,可能就是不想支持这种函数类型了吧,毕竟这是C语言遗留产物。</p>
<h2 id="如何判断一个类型是否是-lambda">如何判断一个类型是否是 lambda</h2>
<p>lambda是C++中的匿名类型,每个新定义的lambda都具有各自不同的类型,一般来说我们无法判断一个类型是否是lambda。</p>
<p>但是有一种特殊的lambda,即捕获列表为空的(captureless)且不是generic的
(使用auto声明参数类型的叫作generic lambda),这种特殊的lambda有一个独有的性质,
就是它能够转换成与它的operator()对应的C语言风格的函数指针,并且指向它的operator()。</p>
<p>我们可以判断一个类型是否具有这种性质,假如具有,那么我们可以猜测这种类型大概率可能就是
这种特殊的lambda,除非用户手动定义了一个具有这种性质的自定义类型,而通常很少有人这么做,也不该这么做。</p>
<p>所以虽然我们无法判断一个类型是否是lambda,但我们可以判断一个类型有可能是
captureless并且non-generic的lambda。判断方法如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span><span class="lnt">86
</span><span class="lnt">87
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// Get a C function pointer type by a member function pointer type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">void</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#if __cplusplus >= 201703
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">noexcept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">noexcept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_cfunction</span><span class="o"><</span><span class="n">Return</span> <span class="p">(</span><span class="n">Object</span><span class="o">::*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="o">></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="n">Return</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">detect_cfunction_t</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">detect_cfunction</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Detect type of callee, which is a pointer to member function operator()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="kt">void</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_callee</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">void</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#if __cplusplus < 201703
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">namespace</span> <span class="n">std</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">void_t</span> <span class="o">=</span> <span class="kt">void</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">detect_callee</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">void_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">T</span><span class="o">::</span><span class="k">operator</span><span class="p">())</span><span class="o">>></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">type</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">T</span><span class="o">::</span><span class="k">operator</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">detect_callee_t</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">detect_callee</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Detect C function style callee type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">detect_c_callee_t</span> <span class="o">=</span> <span class="n">detect_cfunction_t</span><span class="o"><</span><span class="n">detect_callee_t</span><span class="o"><</span><span class="n">T</span><span class="o">>></span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Detect whether T maybe a captureless and non-generic lambda
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">maybe_lambda</span>
</span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">integral_constant</span><span class="o"><</span>
</span></span><span class="line"><span class="cl"> <span class="kt">bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="kt">void</span><span class="o">>::</span><span class="n">value</span> <span class="o">&&</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">is_convertible</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">detect_c_callee_t</span><span class="o"><</span><span class="n">T</span><span class="o">>>::</span><span class="n">value</span><span class="o">></span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>举例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="cp">#define TEST(x) std::cout << #x << ": " << maybe_lambda<x>::value << std::endl;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">A</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">C</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l1</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l2</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">,</span> <span class="p">...){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">l3</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">l4</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&&</span> <span class="n">l5</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l6</span> <span class="o">=</span> <span class="p">[](</span><span class="k">auto</span><span class="p">){};</span> <span class="c1">// generic lambda
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l6</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l7</span> <span class="o">=</span> <span class="p">[</span><span class="o">&</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l7</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l8</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l8</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l9</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l9</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l10</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="k">noexcept</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l10</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l11</span> <span class="o">=</span> <span class="p">[](</span><span class="k">auto</span><span class="p">)</span> <span class="k">noexcept</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l11</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l12</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">int</span><span class="p">)</span> <span class="k">noexcept</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l12</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">A</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="o">&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="o">&&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">>&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">void</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>输出结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">decltype(l1): true
</span></span><span class="line"><span class="cl">decltype(l2): true
</span></span><span class="line"><span class="cl">decltype(l3): true
</span></span><span class="line"><span class="cl">decltype(l4): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l4)>: true
</span></span><span class="line"><span class="cl">decltype(l5): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l5)>: true
</span></span><span class="line"><span class="cl">decltype(l6): false
</span></span><span class="line"><span class="cl">decltype(l7): false
</span></span><span class="line"><span class="cl">decltype(l8): false
</span></span><span class="line"><span class="cl">decltype(l9): true
</span></span><span class="line"><span class="cl">decltype(l10): true
</span></span><span class="line"><span class="cl">decltype(l11): false
</span></span><span class="line"><span class="cl">decltype(l12): false
</span></span><span class="line"><span class="cl">A: false
</span></span><span class="line"><span class="cl">B: false
</span></span><span class="line"><span class="cl">B&: false
</span></span><span class="line"><span class="cl">C: false
</span></span><span class="line"><span class="cl">C&&: false
</span></span><span class="line"><span class="cl">std::function<void(int)>: false
</span></span><span class="line"><span class="cl">std::function<void(int)>&: false
</span></span><span class="line"><span class="cl">int(int): false
</span></span><span class="line"><span class="cl">void(void): false
</span></span><span class="line"><span class="cl">void(int, ...): false
</span></span><span class="line"><span class="cl">int(&)(int): false
</span></span><span class="line"><span class="cl">int(*)(int): false
</span></span><span class="line"><span class="cl">void(*&)(int): false
</span></span><span class="line"><span class="cl">int: false
</span></span><span class="line"><span class="cl">void: false
</span></span><span class="line"><span class="cl">int*: false
</span></span><span class="line"><span class="cl">void*: false
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="如何判断一个类型是否是可调用的">如何判断一个类型是否是可调用的</h2>
<p>可调用基本类型(这里不包括其引用)分两种,一种是具有operator()的类类型,另一种是C语言函数类型及其指针。</p>
<h3 id="1-判断一个类型是否具有operator的类类型">1. 判断一个类型是否具有operator()的类类型</h3>
<p>operator()分两种,一种是非模版函数,一种是模版函数。
对于operator()不是模版函数的类型来说,可以用如下方法判断:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// Whether T has a non-template member operator()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="kt">void</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_callable_class</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">false_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_callable_class</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">void_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">T</span><span class="o">::</span><span class="k">operator</span><span class="p">())</span><span class="o">>></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><em>对于operator()是模版函数的类,目前还没找到判断方法。</em></p>
<p>举例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="cp">#define TEST(x) std::cout << #x << ": " << is_callable_class<x>::value << std::endl;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">A</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">C</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l1</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l2</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">,</span> <span class="p">...){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">l3</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">l4</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&&</span> <span class="n">l5</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l6</span> <span class="o">=</span> <span class="p">[](</span><span class="k">auto</span><span class="p">){};</span> <span class="c1">// generic lambda
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l6</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l7</span> <span class="o">=</span> <span class="p">[</span><span class="o">&</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l7</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l8</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l8</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">A</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="o">&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="o">&&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">>&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">void</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>输出结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">decltype(l1): true
</span></span><span class="line"><span class="cl">decltype(l2): true
</span></span><span class="line"><span class="cl">decltype(l3): true
</span></span><span class="line"><span class="cl">decltype(l4): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l4)>: true
</span></span><span class="line"><span class="cl">decltype(l5): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l5)>: true
</span></span><span class="line"><span class="cl">decltype(l6): false
</span></span><span class="line"><span class="cl">decltype(l7): true
</span></span><span class="line"><span class="cl">decltype(l8): true
</span></span><span class="line"><span class="cl">A: false
</span></span><span class="line"><span class="cl">B: true
</span></span><span class="line"><span class="cl">B&: false
</span></span><span class="line"><span class="cl">C: true
</span></span><span class="line"><span class="cl">C&&: false
</span></span><span class="line"><span class="cl">std::function<void(int)>: true
</span></span><span class="line"><span class="cl">std::function<void(int)>&: false
</span></span><span class="line"><span class="cl">int(int): false
</span></span><span class="line"><span class="cl">void(void): false
</span></span><span class="line"><span class="cl">void(int, ...): false
</span></span><span class="line"><span class="cl">int(&)(int): false
</span></span><span class="line"><span class="cl">int(*)(int): false
</span></span><span class="line"><span class="cl">void(*&)(int): false
</span></span><span class="line"><span class="cl">int: false
</span></span><span class="line"><span class="cl">void: false
</span></span><span class="line"><span class="cl">int*: false
</span></span><span class="line"><span class="cl">void*: false
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="2-判断一个类型是否是c语言函数类型或其指针类型">2. 判断一个类型是否是C语言函数类型或其指针类型</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// whether T is C function
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">false_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#if __cplusplus >= 201703
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">Return</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction</span><span class="o"><</span><span class="n">Return</span><span class="p">(</span><span class="n">Args</span><span class="p">...,</span> <span class="p">...)</span> <span class="k">noexcept</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// whether T is C function pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_cfunction_pointer</span>
</span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">integral_constant</span><span class="o"><</span>
</span></span><span class="line"><span class="cl"> <span class="kt">bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">is_pointer</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">value</span> <span class="o">&&</span>
</span></span><span class="line"><span class="cl"> <span class="n">is_cfunction</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">remove_pointer_t</span><span class="o"><</span><span class="n">T</span><span class="o">>>::</span><span class="n">value</span><span class="o">></span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Whether T is C style callable: C function or C function pointer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_callable_c</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">integral_constant</span><span class="o"><</span>
</span></span><span class="line"><span class="cl"> <span class="kt">bool</span><span class="p">,</span> <span class="n">is_cfunction</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">value</span> <span class="o">||</span> <span class="n">is_cfunction_pointer</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">value</span><span class="o">></span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>举例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="cp">#define TEST(x) std::cout << #x << ": " << is_callable_c<x>::value << std::endl;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">A</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">C</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l1</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l2</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">,</span> <span class="p">...){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">l3</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">l4</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&&</span> <span class="n">l5</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l6</span> <span class="o">=</span> <span class="p">[](</span><span class="k">auto</span><span class="p">){};</span> <span class="c1">// generic lambda
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l6</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l7</span> <span class="o">=</span> <span class="p">[</span><span class="o">&</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l7</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l8</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l8</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">A</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="o">&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="o">&&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">>&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">void</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>输出如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">decltype(l1): false
</span></span><span class="line"><span class="cl">decltype(l2): false
</span></span><span class="line"><span class="cl">decltype(l3): false
</span></span><span class="line"><span class="cl">decltype(l4): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l4)>: false
</span></span><span class="line"><span class="cl">decltype(l5): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l5)>: false
</span></span><span class="line"><span class="cl">decltype(l6): false
</span></span><span class="line"><span class="cl">decltype(l7): false
</span></span><span class="line"><span class="cl">decltype(l8): false
</span></span><span class="line"><span class="cl">A: false
</span></span><span class="line"><span class="cl">B: false
</span></span><span class="line"><span class="cl">B&: false
</span></span><span class="line"><span class="cl">C: false
</span></span><span class="line"><span class="cl">C&&: false
</span></span><span class="line"><span class="cl">std::function<void(int)>: false
</span></span><span class="line"><span class="cl">std::function<void(int)>&: false
</span></span><span class="line"><span class="cl">int(int): true
</span></span><span class="line"><span class="cl">void(void): true
</span></span><span class="line"><span class="cl">void(int, ...): true
</span></span><span class="line"><span class="cl">int(&)(int): false
</span></span><span class="line"><span class="cl">int(*)(int): true
</span></span><span class="line"><span class="cl">void(*&)(int): false
</span></span><span class="line"><span class="cl">int: false
</span></span><span class="line"><span class="cl">void: false
</span></span><span class="line"><span class="cl">int*: false
</span></span><span class="line"><span class="cl">void*: false
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="判断一个类型是否是可调用的">判断一个类型是否是可调用的</h3>
<p>可调用类型就是以上两种情况的综合,is_callable_class或is_callable_c。
另外,如果想包括其引用也判断为可调用类型的话,可以先将某类型decay,然后再判断是否是以上两种情况之一。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">// whether T is callable
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">is_callable</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">integral_constant</span><span class="o"><</span>
</span></span><span class="line"><span class="cl"> <span class="kt">bool</span><span class="p">,</span> <span class="n">is_callable_class</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">value</span> <span class="o">||</span> <span class="n">is_callable_c</span><span class="o"><</span><span class="n">T</span><span class="o">>::</span><span class="n">value</span><span class="o">></span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// whether decay_t<T> is callable
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">decay_is_callable</span> <span class="o">:</span> <span class="n">is_callable</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="n">T</span><span class="o">>></span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>举例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="cp">#define TEST(x) std::cout << #x << ": " << is_callable<x>::value << std::endl;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">A</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">C</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()()</span> <span class="k">const</span> <span class="k">volatile</span> <span class="o">&</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l1</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l2</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">,</span> <span class="p">...){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l2</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">l3</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="n">l4</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l4</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="o">&&</span> <span class="n">l5</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">l5</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l6</span> <span class="o">=</span> <span class="p">[](</span><span class="k">auto</span><span class="p">){};</span> <span class="c1">// generic lambda
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l6</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l7</span> <span class="o">=</span> <span class="p">[</span><span class="o">&</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l7</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">l8</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">int</span><span class="p">){};</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="k">decltype</span><span class="p">(</span><span class="n">l8</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">A</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">B</span><span class="o">&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">C</span><span class="o">&&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">function</span><span class="o"><</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">>&</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">void</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="p">...));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*&</span><span class="p">)(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">TEST</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>输出结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">decltype(l1): true
</span></span><span class="line"><span class="cl">decltype(l2): true
</span></span><span class="line"><span class="cl">decltype(l3): true
</span></span><span class="line"><span class="cl">decltype(l4): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l4)>: true
</span></span><span class="line"><span class="cl">decltype(l5): false
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l5)>: true
</span></span><span class="line"><span class="cl">decltype(l6): false
</span></span><span class="line"><span class="cl">decltype(l7): true
</span></span><span class="line"><span class="cl">decltype(l8): true
</span></span><span class="line"><span class="cl">A: false
</span></span><span class="line"><span class="cl">B: true
</span></span><span class="line"><span class="cl">B&: false
</span></span><span class="line"><span class="cl">C: true
</span></span><span class="line"><span class="cl">C&&: false
</span></span><span class="line"><span class="cl">std::function<void(int)>: true
</span></span><span class="line"><span class="cl">std::function<void(int)>&: false
</span></span><span class="line"><span class="cl">int(int): true
</span></span><span class="line"><span class="cl">void(void): true
</span></span><span class="line"><span class="cl">void(int, ...): true
</span></span><span class="line"><span class="cl">int(&)(int): false
</span></span><span class="line"><span class="cl">int(*)(int): true
</span></span><span class="line"><span class="cl">void(*&)(int): false
</span></span><span class="line"><span class="cl">int: false
</span></span><span class="line"><span class="cl">void: false
</span></span><span class="line"><span class="cl">int*: false
</span></span><span class="line"><span class="cl">void*: false
</span></span></code></pre></td></tr></table>
</div>
</div><p>测试decay_is_callable结果如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="cp">#define TEST(x) std::cout << #x << ": " << decay_is_callable<x>::value << std::endl;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1">// 代码同上,这里省略
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>输出:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">decltype(l1): true
</span></span><span class="line"><span class="cl">decltype(l2): true
</span></span><span class="line"><span class="cl">decltype(l3): true
</span></span><span class="line"><span class="cl">decltype(l4): true
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l4)>: true
</span></span><span class="line"><span class="cl">decltype(l5): true
</span></span><span class="line"><span class="cl">std::decay_t<decltype(l5)>: true
</span></span><span class="line"><span class="cl">decltype(l6): false
</span></span><span class="line"><span class="cl">decltype(l7): true
</span></span><span class="line"><span class="cl">decltype(l8): true
</span></span><span class="line"><span class="cl">A: false
</span></span><span class="line"><span class="cl">B: true
</span></span><span class="line"><span class="cl">B&: true
</span></span><span class="line"><span class="cl">C: true
</span></span><span class="line"><span class="cl">C&&: true
</span></span><span class="line"><span class="cl">std::function<void(int)>: true
</span></span><span class="line"><span class="cl">std::function<void(int)>&: true
</span></span><span class="line"><span class="cl">int(int): true
</span></span><span class="line"><span class="cl">void(void): true
</span></span><span class="line"><span class="cl">void(int, ...): true
</span></span><span class="line"><span class="cl">int(&)(int): true
</span></span><span class="line"><span class="cl">int(*)(int): true
</span></span><span class="line"><span class="cl">void(*&)(int): true
</span></span><span class="line"><span class="cl">int: false
</span></span><span class="line"><span class="cl">void: false
</span></span><span class="line"><span class="cl">int*: false
</span></span><span class="line"><span class="cl">void*: false
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="成员指针类型">成员指针类型</h2>
<h3 id="用子类取基类成员的地址得到什么类型">用子类取基类成员的地址得到什么类型?</h3>
<p>例如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">D</span><span class="o">:</span> <span class="k">public</span> <span class="n">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">D</span><span class="o">::</span><span class="n">i</span><span class="p">),</span> <span class="kt">int</span> <span class="n">B</span><span class="o">::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">D</span><span class="o">::</span><span class="n">B</span><span class="o">::</span><span class="n">i</span><span class="p">),</span> <span class="kt">int</span> <span class="n">B</span><span class="o">::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可见,用子类取基类成员的地址得到的是基类成员指针类型。如上例中 <code>&D::i</code> 就相当于 <code>&D::B::i</code>,
得到的成员指针类型是<code>int B::*</code>。</p>
<h3 id="成员指针类型书写形式中的类类型如果是-cv-qualified-会有什么影响">成员指针类型书写形式中的类类型,如果是 cv-qualified 会有什么影响?</h3>
<p>例如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">ConstB</span> <span class="o">=</span> <span class="k">const</span> <span class="n">B</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="kt">int</span> <span class="n">B</span><span class="o">::*</span><span class="p">,</span> <span class="kt">int</span> <span class="n">ConstB</span><span class="o">::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="kt">int</span> <span class="n">B</span><span class="o">::*</span><span class="p">,</span> <span class="kt">int</span> <span class="n">std</span><span class="o">::</span><span class="n">add_const_t</span><span class="o"><</span><span class="n">B</span><span class="o">>::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="kt">int</span> <span class="n">B</span><span class="o">::*</span><span class="p">,</span> <span class="kt">int</span> <span class="n">std</span><span class="o">::</span><span class="n">add_volatile_t</span><span class="o"><</span><span class="n">B</span><span class="o">>::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="kt">int</span> <span class="n">B</span><span class="o">::*</span><span class="p">,</span> <span class="kt">int</span> <span class="n">std</span><span class="o">::</span><span class="n">add_cv_t</span><span class="o"><</span><span class="n">B</span><span class="o">>::*>::</span><span class="n">value</span><span class="p">,</span> <span class="s">"Never happen"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可见,成员指针类型书写形式中的类类型如果是 cv-qualified,那么C++会自动将其remove_cv,也就是
视作与相应的 成员指针类型书写形式中类类型是 cv-unqualified 的类型 是同一种类型。
并不会像给类类型加引用那样编译报错,例如<code>int std::add_lvalue_reference_t<B>::*</code>会编译报错
“type ‘add_lvalue_reference_t<B>’ (aka ‘B &’) cannot be used prior to ‘::’ because it has no members”。</p>