<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Development on 番茄🍅杂货铺</title>
    <link>https://blog.tomatostore.top/tags/development/</link>
    <description>Recent content in Development on 番茄🍅杂货铺</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 30 Oct 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.tomatostore.top/tags/development/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>C&#43;&#43;：CRTP（奇异递归模板模式）实用入门</title>
      <link>https://blog.tomatostore.top/posts/2025/10/cpp-crtp-intruduction/</link>
      <pubDate>Thu, 30 Oct 2025 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2025/10/cpp-crtp-intruduction/</guid>
      <description>用清晰示例解释 CRTP 的概念、优势、典型用法与局限</description>
      <content:encoded><![CDATA[<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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyStubService</span> <span class="o">:</span> <span class="k">public</span> <span class="n">DbusServer</span><span class="o">&lt;</span><span class="n">MyStubService</span><span class="o">&gt;</span> <span class="p">{};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>咨询了 DeepSeek 后得知这是 C++ 中的 <strong>CRTP（Curiously Recurring Template Pattern，奇异递归模板模式）</strong>。</p>
<p>CRTP 是一种借助模板实现<strong>编译时多态</strong>的技术，核心思想是：<strong>类模板以其派生类作为模板参数</strong>。</p>
<h2 id="crtp-的优势">CRTP 的优势</h2>
<ol>
<li><strong>性能优势</strong>：避免了虚函数调用的运行时开销</li>
<li><strong>编译时优化</strong>：编译器可以进行更好的内联和优化</li>
<li><strong>类型安全</strong>：在编译时捕获类型错误</li>
<li><strong>减少二进制大小</strong>：不需要虚函数表</li>
</ol>
<h2 id="crtp-基本语法结构">CRTP 基本语法结构</h2>
<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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Base</span> <span class="p">{</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Derived</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Base</span><span class="o">&lt;</span><span class="n">Derived</span><span class="o">&gt;</span> <span class="p">{</span>  <span class="c1">// 关键：派生类将自己作为模板参数传递给基类
</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><h2 id="crtp-主要应用场景">CRTP 主要应用场景</h2>
<h3 id="1-静态多态编译时多态">1. 静态多态（编译时多态）</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><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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Animal</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">speak</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">&lt;</span><span class="n">Derived</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">speakImpl</span><span class="p">();</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></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="nf">run</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">&lt;</span><span class="n">Derived</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">runImpl</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Dog</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Animal</span><span class="o">&lt;</span><span class="n">Dog</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">speakImpl</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">&lt;&lt;</span> <span class="s">&#34;Woof!&#34;</span> <span class="o">&lt;&lt;</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="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="nf">runImpl</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">&lt;&lt;</span> <span class="s">&#34;Running on four legs&#34;</span> <span class="o">&lt;&lt;</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="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">class</span> <span class="nc">Cat</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Animal</span><span class="o">&lt;</span><span class="n">Cat</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">speakImpl</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">&lt;&lt;</span> <span class="s">&#34;Meow!&#34;</span> <span class="o">&lt;&lt;</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="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="nf">runImpl</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">&lt;&lt;</span> <span class="s">&#34;Running gracefully&#34;</span> <span class="o">&lt;&lt;</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="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="c1">// 使用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">makeAnimalSpeak</span><span class="p">(</span><span class="n">Animal</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">animal</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">animal</span><span class="p">.</span><span class="n">speak</span><span class="p">();</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><h3 id="2-对象计数">2. 对象计数</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Counter</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="kt">int</span> <span class="n">count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">protected</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Counter</span><span class="p">()</span> <span class="p">{</span> <span class="o">++</span><span class="n">count</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">Counter</span><span class="p">(</span><span class="k">const</span> <span class="n">Counter</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span> <span class="o">++</span><span class="n">count</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">~</span><span class="n">Counter</span><span class="p">()</span> <span class="p">{</span> <span class="o">--</span><span class="n">count</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="kt">int</span> <span class="n">getCount</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="n">count</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="c1">// 静态成员初始化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">Counter</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">count</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="c1">// 使用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">MyClass</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Counter</span><span class="o">&lt;</span><span class="n">MyClass</span><span class="o">&gt;</span> <span class="p">{</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">AnotherClass</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Counter</span><span class="o">&lt;</span><span class="n">AnotherClass</span><span class="o">&gt;</span> <span class="p">{</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="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="3-链式调用">3. 链式调用</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Chainable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">self</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">Derived</span><span class="o">&amp;&gt;</span><span class="p">(</span><span class="o">*</span><span class="k">this</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="n">Derived</span><span class="o">&amp;</span> <span class="n">setX</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</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">self</span><span class="p">().</span><span class="n">setXImpl</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nf">self</span><span class="p">();</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></span><span class="line"><span class="cl">    <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">setY</span><span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">self</span><span class="p">().</span><span class="n">setYImpl</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nf">self</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Point</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Chainable</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Point</span><span class="o">&amp;</span> <span class="n">setXImpl</span><span class="p">(</span><span class="kt">int</span> <span class="n">x_</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x_</span><span class="p">;</span> <span class="k">return</span> <span class="o">*</span><span class="k">this</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">Point</span><span class="o">&amp;</span> <span class="n">setYImpl</span><span class="p">(</span><span class="kt">int</span> <span class="n">y_</span><span class="p">)</span> <span class="p">{</span> <span class="n">y</span> <span class="o">=</span> <span class="n">y_</span><span class="p">;</span> <span class="k">return</span> <span class="o">*</span><span class="k">this</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="kt">void</span> <span class="nf">print</span><span class="p">()</span> <span class="k">const</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">&lt;&lt;</span> <span class="s">&#34;Point(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">y</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span> <span class="o">&lt;&lt;</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="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="c1">// 使用：链式调用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Point</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="p">.</span><span class="n">setX</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="n">setY</span><span class="p">(</span><span class="mi">20</span><span class="p">).</span><span class="n">print</span><span class="p">();</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="4-实现运算符重载">4. 实现运算符重载</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Comparable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Derived</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">equals</span><span class="p">(</span><span class="n">other</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">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="k">const</span> <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">!</span><span class="k">static_cast</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Derived</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">equals</span><span class="p">(</span><span class="n">other</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Person</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Comparable</span><span class="o">&lt;</span><span class="n">Person</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</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">string</span> <span class="n">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">age</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Person</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">)</span> <span class="o">:</span> <span class="n">name</span><span class="p">(</span><span class="n">n</span><span class="p">),</span> <span class="n">age</span><span class="p">(</span><span class="n">a</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="kt">bool</span> <span class="nf">equals</span><span class="p">(</span><span class="k">const</span> <span class="n">Person</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">name</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="n">name</span> <span class="o">&amp;&amp;</span> <span class="n">age</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="n">age</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="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="5-静态接口检查约束派生类的必备成员">5. 静态接口检查（约束派生类的必备成员）</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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MustHaveFoo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">callFoo</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_v</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="o">&amp;</span><span class="n">Derived</span><span class="o">::</span><span class="n">foo</span><span class="p">),</span> <span class="kt">void</span><span class="p">(</span><span class="n">Derived</span><span class="o">::*</span><span class="p">)()</span><span class="o">&gt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                      <span class="s">&#34;Derived must define void foo() member&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">Derived</span><span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">foo</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">OK</span> <span class="o">:</span> <span class="k">public</span> <span class="n">MustHaveFoo</span><span class="o">&lt;</span><span class="n">OK</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">foo</span><span class="p">()</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>也可用 C++20 Concepts 直接约束：</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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">concept</span> <span class="n">HasFoo</span> <span class="o">=</span> <span class="k">requires</span><span class="p">(</span><span class="n">T</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> <span class="n">t</span><span class="p">.</span><span class="n">foo</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="k">template</span> <span class="o">&lt;</span><span class="n">HasFoo</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MustHaveFoo2</span> <span class="p">{</span> <span class="cm">/* ... */</span> <span class="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="6-空基类优化ebo">6. 空基类优化（EBO）</h3>
<p>CRTP 基类常为空（仅编译期行为），作为空基类被继承时通常不占用额外空间，有助于零开销地叠加特性。</p>
<h3 id="7-bartonnackman-技巧基于-crtp-的友元运算符">7. Barton–Nackman 技巧（基于 CRTP 的友元运算符）</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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Derived</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Orderable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">friend</span> <span class="kt">bool</span> <span class="k">operator</span><span class="o">&lt;</span><span class="p">(</span><span class="k">const</span> <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">Derived</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">less</span><span class="p">(</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Node</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Orderable</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">less</span><span class="p">(</span><span class="k">const</span> <span class="n">Node</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">key</span> <span class="o">&lt;</span> <span class="n">other</span><span class="p">.</span><span class="n">key</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">key</span><span class="p">{</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><h2 id="crtp-的局限性">CRTP 的局限性</h2>
<ol>
<li><strong>编译时绑定</strong>：不能在运行时动态改变行为</li>
<li><strong>模板复杂性</strong>：错误信息可能难以理解</li>
<li><strong>代码膨胀</strong>：每个派生类都会实例化一个不同的基类模板</li>
</ol>
<h2 id="最佳实践与常见陷阱">最佳实践与常见陷阱</h2>
<ul>
<li><strong>只在需要零开销和编译期已知类型时使用</strong>，否则优先简单的虚函数或组合。</li>
<li>基类中用 <code>static_cast&lt;Derived*&gt;</code>/<code>static_cast&lt;const Derived*&gt;</code> 调用派生实现；不要用 <code>dynamic_cast</code>。</li>
<li>避免通过基类指针/引用“多态地”存放不同派生对象（CRTP 不是为此设计）。</li>
<li>多重继承下的 CRTP：注意菱形结构与方法可见性，必要时用 <code>using Derived::method</code> 暴露成员。</li>
<li>为 CRTP 基类提供 <code>protected</code> 构造函数，避免被直接实例化。</li>
<li>若需接口约束，结合 <code>static_assert</code> 或 Concepts，尽早在编译期报错。</li>
<li>链式 API 返回 <code>Derived&amp;</code>/<code>const Derived&amp;</code>，避免返回 <code>*this</code> 的基类引用。</li>
</ul>
<h2 id="何时使用--不使用-crtp">何时使用 / 不使用 CRTP</h2>
<ul>
<li>使用：
<ul>
<li><strong>静态多态</strong>、热点路径需要最大化内联与去虚拟化。</li>
<li>可复用的“mixin 特性”（日志、计数、对比、序列化接口）按需叠加。</li>
<li>需要在编译期强制派生类提供某些接口（静态约束）。</li>
</ul>
</li>
<li>不使用：
<ul>
<li>需要在运行时根据配置/输入切换具体实现。</li>
<li>需要通过基类容器存放异构对象并统一调度。</li>
<li>团队对模板元编程不熟，维护成本高于收益。</li>
</ul>
</li>
</ul>
<h2 id="与虚函数多态的对比">与虚函数多态的对比</h2>
<ul>
<li><strong>分发时机</strong>：
<ul>
<li>虚函数是运行时分发（需 vtable），可通过基类指针/引用统一处理异构对象。</li>
<li>CRTP 是编译时分发，要求在编译期就知道具体类型，换来零开销。</li>
</ul>
</li>
<li><strong>扩展方式</strong>：
<ul>
<li>虚函数通过覆盖虚方法扩展行为。</li>
<li>CRTP 通过“静态接口”约束派生类提供实现，基类用 <code>static_cast&lt;Derived*&gt;</code> 调用。</li>
</ul>
</li>
<li><strong>适用场景</strong>：
<ul>
<li>运行时需要真正的动态绑定 → 选虚函数。</li>
<li>性能敏感、类型在编译期已知、可模板化 → 选 CRTP。</li>
</ul>
</li>
</ul>
<h2 id="faq">FAQ</h2>
<ul>
<li>为什么叫“奇异递归”？
<ul>
<li>因为基类模板的实参“递归地”引用了派生类本身，看起来很“奇怪”，但这是合法且有用的模板技巧。</li>
</ul>
</li>
<li>可以多层套 CRTP 吗？
<ul>
<li>可以，但要控制复杂度，注意方法名冲突与可读性。</li>
</ul>
</li>
<li>和 Concepts 是什么关系？
<ul>
<li>Concepts 负责“约束”，CRTP 负责“复用 + 分发”。两者可结合使用，提升错误信息友好度与可维护性。</li>
</ul>
</li>
</ul>
<h2 id="小结">小结</h2>
<p>CRTP 是 C++ 模板元编程中的重要模式，在性能敏感场景（如游戏开发、高频交易等）尤为常见。它在不引入虚函数开销的前提下提供多态式的扩展能力，适合用于“编译期就能决定行为”的问题。但需要权衡模板复杂度与可维护性，避免过度抽象。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Ask ChatGPT/Cursor: Preprocessor Macro Doesn&#39;t Work in Swift</title>
      <link>https://blog.tomatostore.top/posts/2024/10/preprocessor-macro-in-swift/</link>
      <pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/10/preprocessor-macro-in-swift/</guid>
      <description>Xcode 中如何定义 Swift 适用的预处理宏</description>
      <content:encoded><![CDATA[<h2 id="the-problem">The Problem</h2>
<p>I defined the preprocessor macro <code>USING_REVENUE_CAT=1</code> in my project target&rsquo;s Build Settings under <strong>Preprocessor Macros</strong>.</p>
<p>However, when I tried to use it in my <code>Swift</code> file with the following code, I received an error indicating that the module <code>SwiftyStoreKit</code> could not be found. This was puzzling because I expected the macro to work similarly to how it does in <code>Objective-C</code>.</p>
<p><img loading="lazy" src="/images/Preprocessor-Macros.png" alt="Preprocessor-Macros in Xcode"  /></p>
<h2 id="the-solution">The Solution</h2>
<p>Asked both <code>ChatGPT</code> and <code>Cursor</code> for help, and they gave me similar answers as following:</p>
<p><code>Swift</code> does not recognize preprocessor macros defined in the Build Settings the same way <code>Objective-C</code> does. Instead, you need to define custom flags specifically for <code>Swift</code>.</p>
<h3 id="steps-to-define-a-preprocessor-macro-for-swift">Steps to Define a Preprocessor Macro for Swift</h3>
<ol>
<li>
<p><strong>Navigate to Build Settings:</strong>
Open your project in Xcode and select your target. Then, go to the <strong>Build Settings</strong> tab.</p>
</li>
<li>
<p><strong>Find Swift Compiler - Custom Flags:</strong>
Scroll down to the <strong>Swift Compiler - Custom Flags</strong> section.</p>
</li>
<li>
<p><strong>Add the Custom Flag:</strong>
In the <strong>Other Swift Flags</strong> field, add the following:</p>
<pre tabindex="0"><code>USING_REVENUE_CAT
</code></pre></li>
</ol>
<p>This tells the <code>Swift</code> compiler to define the <code>USING_REVENUE_CAT</code> flag, allowing you to use it in your <code>Swift</code> code.</p>
<h3 id="updated-swift-code">Updated Swift Code</h3>
<p>After adding the custom flag, your <code>Swift</code> code should work as intended:</p>
<p><img loading="lazy" src="/images/Swift-Compiler_Customer-Flags.png" alt="Swift-Compiler_Customer-Flags"  /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>解决 Xcode 15.4 在 macOS 14.5 上开发 Adobe Illustrator Plugin 时 Python 命令未找到问题</title>
      <link>https://blog.tomatostore.top/posts/2024/09/python/</link>
      <pubDate>Sun, 01 Sep 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/09/python/</guid>
      <description>Solving the Python Command Not Found Issue When Developing Adobe Illustrator Plugin with Xcode 15.4 on macOS 14.5</description>
      <content:encoded><![CDATA[<h2 id="一问题描述">一、问题描述</h2>
<p>在使用 Xcode 15.4 在 macOS 14.5 上尝试开发 Adobe Illustrator Plugin 时，在编译 Adobe Illustrator 2023 SDK 的 sample 过程中出现错误：</p>
<pre tabindex="0"><code>/Users/aidy/Workspace/Adobe Illustrator 2023 SDK/samplecode/StrokeFilter/build/StrokeFilter.build/Default/StrokeFilter.build/Script-FDD9160721AC093D0018B958.sh: line 2: python: command not found
Command PhaseScriptExecution failed with a nonzero exit code
</code></pre><p>查看 <code>Script-FDD9160721AC093D0018B958.sh</code> 文件内容为：</p>
<pre tabindex="0"><code>#!/bin/sh
python ../../tools/pipl/create_pipl.py -input &#39;[{&#34;name&#34;:&#34;StrokeFilter&#34;,&#34;entry_point&#34; : &#34;PluginMain&#34;}]&#39;
</code></pre><h2 id="二尝试过程">二、尝试过程</h2>
<p>首先怀疑是没有安装 <code>xcode command line tool</code>，但确认已经安装过了。
接着考虑可能是没有安装 <code>Python</code>。通过 <code>brew install python</code> 安装了 <code>Python3</code>，但 <code>Xcode</code> 中仍然提示<code>python: command not found</code>。
从 <code>Adobe Community</code> 搜索得知这里需要 <code>Python2</code>，于是使用 <code>pyenv</code> 安装了 <code>Python2</code>，并设置 <code>pyenv global 2.7.18</code>。在 <code>Terminal</code> 中执行 <code>python -V</code> 输出是 <code>Python 2.7.18</code>，然而 <code>Xcode build</code> 依旧报错。
尝试了 <code>sudo ln /Users/&lt;user&gt;/.pyenv/shims/python /Library/Developer/CommandLineTools/usr/bin/python</code>，但没有作用。</p>
<h2 id="三最终解决办法">三、最终解决办法</h2>
<p>通过 <code>sudo ln /Users/&lt;user&gt;/.pyenv/shims/python /usr/local/bin/python</code> 设置 <code>/usr/local/bin</code> 的 <code>link</code>，解决了问题。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>[Linux] Share environment variables with root user</title>
      <link>https://blog.tomatostore.top/posts/2024/07/share-env-when-running-cmd-with-sudo/</link>
      <pubDate>Thu, 25 Jul 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/07/share-env-when-running-cmd-with-sudo/</guid>
      <description>Keep current user&amp;#39;s env variables when running sudo command</description>
      <content:encoded><![CDATA[<h2 id="linux-share-environment-variables-with-root-user">[Linux] Share environment variables with root user</h2>
<h4 id="problem">Problem</h4>
<p>There are some environment variabels (e.g. <code>http_proxy</code>) set for current user on Ubuntu 20.4, but when running some commands with <code>sudo</code> (like <code>sudo apt update</code>), those environment variables are not available anymore.</p>
<h4 id="solution">Solution</h4>
<ol>
<li><code>sudo -E</code></li>
</ol>
<p>If you are running commands manually, it&rsquo;s possible to preserve evn setting by adding <code>-E</code> option.</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-shell" data-lang="shell"><span class="line"><span class="cl">sudo -E apt update
</span></span></code></pre></td></tr></table>
</div>
</div><ol start="2">
<li><code>sudo visudo</code></li>
</ol>
<p>Using option <code>-E</code> may not work in the cases that the commands with <code>sudo</code> are run in script.
To make the specific environment settings shared with <code>sudo</code>, it can be configured with <code>visudo</code>.</p>
<p>Using following command:</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-shell" data-lang="shell"><span class="line"><span class="cl">sudo visudo
</span></span></code></pre></td></tr></table>
</div>
</div><p>In opened nano editor, find the line begins with <code>Defaults        env_keep</code>, modify it as following to make <code>http_proxy</code> and <code>https_proxy</code> settings be keeped when running commands using <code>sudo</code>:</p>
<pre tabindex="0"><code>Defaults        env_keep += &#34;https_proxy http_proxy&#34;
</code></pre><p>Then, when running <code>sudo apt update</code>, those proxy env variables will kept.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to enable AddressSanitizer(ASan) for C&#43;&#43; Project</title>
      <link>https://blog.tomatostore.top/posts/2024/05/how-to-enable-asan-in-cpp-project/</link>
      <pubDate>Fri, 24 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/05/how-to-enable-asan-in-cpp-project/</guid>
      <description>The tool to detect runtime memory leak</description>
      <content:encoded><![CDATA[<p>To integrate AddressSanitizer(ASan) to an existing project, just add the compile option <code>-fsanitize=address</code> and generate debug infor with <code>-g</code> in <code>CMakeLists.txt</code>.</p>
<pre tabindex="0"><code>option(ENABLE_ASAN &#34;enable AddressSanitizer&#34; OFF)

if(ENABLE_ASAN)
    set(CMAKE_CXX_FLAGS &#34;${CMAKE_CXX_FLAGS} -fsanitize=address&#34;)
    set(CMAKE_CXX_FLAGS &#34;-O -g&#34;)
    set(CMAKE_C_FLAGS &#34;-O -g&#34;)
endif()
</code></pre><p>Compile the project:</p>
<pre tabindex="0"><code>mkdir build
cd build
cmake -DENABLE_ASAN=ON ..
cmake --build .
</code></pre><p>After the build, using following command to start the program:</p>
<pre tabindex="0"><code>ASAN_OPTIONS=detect_leaks=1 ./a.out
</code></pre><p>It will print detail info when memory leak occurs.</p>
<pre tabindex="0"><code>=================================================================
==12345==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7f3d8b4fbb90 in __interceptor_new (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xde90)
    #1 0x4006d6 in createLeak /path/to/your/project/main.cpp:4
    #2 0x4006f8 in main /path/to/your/project/main.cpp:9
    #3 0x7f3d8b0d283f in __libc_start_main (/lib64/libc.so.6+0x2383f)

SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).
</code></pre>]]></content:encoded>
    </item>
    
    <item>
      <title>Install docker in Ubuntu 20 and config network proxy</title>
      <link>https://blog.tomatostore.top/posts/2024/05/install-docker-on-ubuntu-20/</link>
      <pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/05/install-docker-on-ubuntu-20/</guid>
      <description>在Ubuntu 20中安装 Docker、配置网络代理</description>
      <content:encoded><![CDATA[<h2 id="steps-to-install-docker-on-ubuntu-20">steps to install docker on Ubuntu 20</h2>
<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-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
</span></span><span class="line"><span class="cl">curl -fsSL https://download.docker.com/linux/ubuntu/gpg <span class="p">|</span> sudo apt-key add -
</span></span><span class="line"><span class="cl">sudo add-apt-repository <span class="s2">&#34;deb [arch=amd64] https://download.docker.com/linux/ubuntu </span><span class="k">$(</span>lsb_release -cs<span class="k">)</span><span class="s2"> stable&#34;</span>
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install docker-ce
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="verify-the-installation">verify the installation</h2>
<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-shell" data-lang="shell"><span class="line"><span class="cl">sudo systemctl status docker
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="add-current-user-to-docker-group">add current user to docker group</h2>
<ul>
<li>in order to avoid adding <code>sudo</code> when running docker command</li>
</ul>
<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-shell" data-lang="shell"><span class="line"><span class="cl">sudo usermod -aG docker <span class="si">${</span><span class="nv">USER</span><span class="si">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="network-proxy-settings">Network proxy settings</h2>
<h3 id="dockerd-proxy">Dockerd Proxy</h3>
<p>To configure the proxy for <code>dockerd</code>, which is managed by <code>systemd</code>, create and edit a configuration file:</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-sh" data-lang="sh"><span class="line"><span class="cl">sudo mkdir -p /etc/systemd/system/docker.service.d
</span></span><span class="line"><span class="cl">sudo touch /etc/systemd/system/docker.service.d/proxy.conf
</span></span></code></pre></td></tr></table>
</div>
</div><p>Add the following to <code>proxy.conf</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;HTTP_PROXY=http://proxy.example.com:8080/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;HTTPS_PROXY=http://proxy.example.com:8080/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;NO_PROXY=localhost,127.0.0.1,.example.com&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Replace <code>proxy.example.com:8080</code> with your proxy address.</p>
<h3 id="container-proxy">Container Proxy</h3>
<p>To configure proxy settings for containers, edit <code>~/.docker/config.json</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">&#34;proxies&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&#34;default&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;httpProxy&#34;</span><span class="p">:</span> <span class="s2">&#34;http://proxy.example.com:8080&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;httpsProxy&#34;</span><span class="p">:</span> <span class="s2">&#34;http://proxy.example.com:8080&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;noProxy&#34;</span><span class="p">:</span> <span class="s2">&#34;localhost,127.0.0.1,.example.com&#34;</span>
</span></span><span class="line"><span class="cl">   <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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>For container runtime proxies, use the <code>-e</code> option to set environment variables.</p>
<h3 id="docker-build-proxy">Docker Build Proxy</h3>
<p>For <code>docker build</code>, inject proxy settings using <code>--build-arg</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">docker build . <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --build-arg <span class="s2">&#34;HTTP_PROXY=http://proxy.example.com:8080/&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --build-arg <span class="s2">&#34;HTTPS_PROXY=http://proxy.example.com:8080/&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --build-arg <span class="s2">&#34;NO_PROXY=localhost,127.0.0.1,.example.com&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -t your/image:tag
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="applying-changes">Applying Changes</h3>
<p>To apply the changes:</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-sh" data-lang="sh"><span class="line"><span class="cl">sudo systemctl daemon-reload
</span></span><span class="line"><span class="cl">sudo systemctl restart docker
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="trouble-shooting">Trouble shooting</h2>
<h3 id="when-running-command-sudo-apt-update-it-has-following-error">when running command <code>sudo apt update</code>, it has following error</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">Err:5 https://download.docker.com/linux/ubuntu focal Release                                            
</span></span><span class="line"><span class="cl">  Could not handshake: The TLS connection was non-properly terminated. <span class="o">[</span>IP: &lt;xx.xxx.xx.xxx&gt; 3128<span class="o">]</span>
</span></span><span class="line"><span class="cl">Hit:6 http://security.ubuntu.com/ubuntu focal-security InRelease                                        
</span></span><span class="line"><span class="cl">Hit:7 http://us.archive.ubuntu.com/ubuntu focal-security InRelease
</span></span><span class="line"><span class="cl">Reading package lists... Done
</span></span><span class="line"><span class="cl">E: The repository <span class="s1">&#39;https://download.docker.com/linux/ubuntu focal Release&#39;</span> does not have a Release file.
</span></span><span class="line"><span class="cl">N: Updating from such a repository can<span class="err">&#39;</span>t be <span class="k">done</span> securely, and is therefore disabled by default.
</span></span><span class="line"><span class="cl">N: See apt-secure<span class="o">(</span>8<span class="o">)</span> manpage <span class="k">for</span> repository creation and user configuration details.
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="solution">Solution</h4>
<p>According to <a href="https://askubuntu.com/a/1289675/1578724">this answer</a>, modify <code>/etc/apt/apt.config</code> to make sure the proxy settings are correct, especially the <code>https</code> settings.</p>
<ul>
<li><strong>Wrong config:</strong></li>
</ul>
<pre tabindex="0"><code>Acquire::http::proxy &#34;http://proxy.mydom.it:8080&#34;;
Acquire::https::proxy &#34;https://proxy.mydom.it:8080&#34;;
</code></pre><ul>
<li><strong>Good config:</strong></li>
</ul>
<pre tabindex="0"><code>Acquire::http::proxy &#34;http://proxy.mydom.it:8080&#34;;
Acquire::https::proxy &#34;http://proxy.mydom.it:8080&#34;;
</code></pre>]]></content:encoded>
    </item>
    
    <item>
      <title>VSCode: 正则搜索匹配多行多个关键字</title>
      <link>https://blog.tomatostore.top/posts/2024/05/vscode-regexp-match-multiple-words-in-diff-lines/</link>
      <pubDate>Tue, 07 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2024/05/vscode-regexp-match-multiple-words-in-diff-lines/</guid>
      <description>Match two words in diff lines in VSCode</description>
      <content:encoded><![CDATA[<p>场景：<code>QML</code> 项目中搜索 <code>Button</code> 控件并使用了 <code>background</code> 属性的代码。</p>
<p>正则表达式写法： <code>Button.*(?:\n.*(?:\n.*)){0,10}.*background</code></p>
<p>匹配效果：</p>
<p><img loading="lazy" src="/images/vscode-regexp-match-multiple-words-in-diff-lines.png" alt="vscode-regexp-match-multiple-words-in-diff-lines"  /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>iOS开发-加载其他语言的String资源</title>
      <link>https://blog.tomatostore.top/posts/2023/11/ios-localized-string-in-diff-languages/</link>
      <pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/11/ios-localized-string-in-diff-languages/</guid>
      <description>Load Settings.bundle in diff languages</description>
      <content:encoded><![CDATA[<p>在开发iOS应用时，我们可能会遇到需要使用不同语言的字符串资源的情况。比如，当iOS的语言设置为A，而我们的应用需要使用语言B。
这里有一个语音计算器，用户可以在计算时选择不同的语音朗读语言，而无需改变整个iOS的语言设置。例如，如果我们的手机语言设置为英语，但我们希望计算器能用中文朗读计算结果。</p>
<a href="https://apps.apple.com/cn/app/id1501166219">
  <img src="/images/calculator-settings.jpg" align="center" style="width: 80%; height: 80%;"/>
</a>
<p>为了实现这个功能，我们可以使用iOS的本地化机制。有两种常见的解决方案：</p>
<ol>
<li><strong>加载相应语言的资源文件</strong></li>
</ol>
<p>我们可以为每种语言创建一个资源文件，并在其中添加我们的本地化字符串。然后，我们可以根据用户选择的语言，从相应的资源文件中加载字符串。</p>
<p>在Swift中，我们可以使用如下方式实现：</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-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">extension</span> <span class="nc">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">localized</span><span class="p">:</span> <span class="nb">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// TalkingNumCalUserDefaults.voiceLang has value like &#39;en-US&#39;, &#39;fr-FR&#39;, &#39;de-DE&#39; etc.</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="kd">let</span> <span class="nv">lang</span> <span class="p">=</span> <span class="n">Locale</span><span class="p">(</span><span class="n">identifier</span><span class="p">:</span> <span class="n">TalkingNumCalUserDefaults</span><span class="p">.</span><span class="n">voiceLang</span><span class="p">).</span><span class="n">languageCode</span> <span class="p">{</span> <span class="c1">// e.g. en, jp, zh ...</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="kd">let</span> <span class="nv">path</span> <span class="p">=</span> <span class="n">Bundle</span><span class="p">.</span><span class="n">main</span><span class="p">.</span><span class="n">path</span><span class="p">(</span><span class="n">forResource</span><span class="p">:</span> <span class="n">lang</span><span class="p">,</span> <span class="n">ofType</span><span class="p">:</span> <span class="s">&#34;lproj&#34;</span><span class="p">),</span> <span class="kd">let</span> <span class="nv">bundle</span> <span class="p">=</span> <span class="n">Bundle</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="kd">let</span> <span class="nv">string</span> <span class="p">=</span> <span class="n">bundle</span><span class="p">.</span><span class="n">localizedString</span><span class="p">(</span><span class="n">forKey</span><span class="p">:</span> <span class="kc">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="kc">nil</span><span class="p">,</span> <span class="n">table</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">string</span>
</span></span><span class="line"><span class="cl">            <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">return</span> <span class="n">NSLocalizedString</span><span class="p">(</span><span class="kc">self</span><span class="p">,</span> <span class="n">comment</span><span class="p">:</span> <span class="s">&#34;&#34;</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>这个解决方案需要我们预先准备好所有可能用到的语言的资源文件。当用户选择了一种语言后，我们从对应的资源文件中加载字符串。如果没有找到对应的资源文件，我们就返回一个未本地化的字符串。</p>
<ol start="2">
<li><strong>设置Bundle的语言</strong></li>
</ol>
<p>我们可以先通过用户选择的语言设置Bundle的语言，然后直接从Bundle中获取本地化的字符串。</p>
<p>在Swift中，我们可以使用如下方式实现：</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-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">extension</span> <span class="nc">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">localized</span><span class="p">:</span> <span class="nb">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// TalkingNumCalUserDefaults.voiceLang has value like &#39;en-US&#39;, &#39;fr-FR&#39;, &#39;de-DE&#39; etc.</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="kd">let</span> <span class="nv">lang</span> <span class="p">=</span> <span class="n">Locale</span><span class="p">(</span><span class="n">identifier</span><span class="p">:</span> <span class="n">TalkingNumCalUserDefaults</span><span class="p">.</span><span class="n">voiceLang</span><span class="p">).</span><span class="n">languageCode</span> <span class="p">{</span> <span class="c1">// e.g. en, jp, zh ...</span>
</span></span><span class="line"><span class="cl">            <span class="n">Bundle</span><span class="p">.</span><span class="n">setLanguage</span><span class="p">(</span><span class="n">lang</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">return</span> <span class="n">NSLocalizedString</span><span class="p">(</span><span class="kc">self</span><span class="p">,</span> <span class="n">tableName</span><span class="p">:</span> <span class="kc">nil</span><span class="p">,</span> <span class="n">bundle</span><span class="p">:</span> <span class="n">Bundle</span><span class="p">.</span><span class="n">main</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="n">comment</span><span class="p">:</span> <span class="s">&#34;&#34;</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>这个解决方案需要我们在每次用户选择一种新的语言时，都重新设置一次Bundle的语言。然后，我们从Bundle中获取本地化的字符串。如果没有找到对应的字符串，我们就返回一个未本地化的字符串。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Variadic Template and Fold Expression in C&#43;&#43;</title>
      <link>https://blog.tomatostore.top/posts/2023/08/cpp-variadic-template-and-fold-expression/</link>
      <pubDate>Mon, 21 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/08/cpp-variadic-template-and-fold-expression/</guid>
      <description>C&#43;&#43; 可变模板和折叠表达式</description>
      <content:encoded><![CDATA[<p>遇到如下代码，对于 <code>func2</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">DataStruct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">DataStruct</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">T</span> <span class="n">n</span><span class="p">)</span><span class="o">:</span> <span class="n">index</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="n">value</span><span class="p">(</span><span class="n">n</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="kt">int</span> <span class="n">index</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">T</span> <span class="n">value</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">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">func1</span><span class="p">(</span><span class="n">string</span> <span class="n">prefix</span><span class="p">,</span> <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">T</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">__FUNCTION__</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">prefix</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">T</span><span class="o">&gt;</span> <span class="c1">// mark 1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">func2</span><span class="p">(</span><span class="n">string</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">DataStruct</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;&amp;</span><span class="p">...</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// mark 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">(</span><span class="n">func1</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">index</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">value</span><span class="p">),</span> <span class="p">...);</span>  <span class="c1">// mark 3
</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></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></span><span class="line"><span class="cl">    <span class="n">func2</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&#34;hi &#34;</span><span class="p">,</span> <span class="n">DataStruct</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="s">&#34;Tom&#34;</span><span class="p">),</span> <span class="n">DataStruct</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">29</span><span class="p">,</span> <span class="s">&#34;Mason&#34;</span><span class="p">),</span> <span class="n">DataStruct</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">999</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;done</span><span class="se">\n</span><span class="s">&#34;</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="c1">// execute result
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">func1(hi , 12, Tom)
</span></span></span><span class="line"><span class="cl"><span class="cm">func1(hi , 29, Mason)
</span></span></span><span class="line"><span class="cl"><span class="cm">func1(hi , 100, 999)
</span></span></span><span class="line"><span class="cl"><span class="cm">done
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>查询后得知是 <code>C++</code> 的可变模板(<code>variadic template</code>)和折叠表达式(<code>fold expression</code>)。</p>
<h2 id="可变模板variadic-template">可变模板（Variadic Template）</h2>
<p>可变模板是 C++11 引入的功能，允许模板接受<em>不定数量的模板参数</em>。这对于需要处理多个参数类型或数量的情况非常有用。例如：</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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">coutX</span><span class="p">()</span> <span class="p">{}</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="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Types</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">coutX</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">,</span> <span class="k">const</span> <span class="n">Types</span><span class="o">&amp;</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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">t</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="c1">// cout 1st argument
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">coutX</span><span class="p">(</span><span class="n">args</span><span class="p">...);</span> <span class="c1">// 对可变参数递归调用 coutX
</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>其中非模板重载函数 <code>contX()</code> 是递归调用的终止条件。</p>
<h2 id="折叠表达式fold-expression">折叠表达式（Fold Expression）</h2>
<p>折叠表达式是 <code>C++17</code> 为配合 <code>Variadic Template</code> 使用引入的功能，它允许在模板展开过程中进行一元或二元操作。折叠表达式有两种形式：左折叠和右折叠。</p>
<p>对应的展开关系如下：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">Fold Expression</th>
          <th style="text-align: right">Evaluation</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left"><code>(E op ...)</code></td>
          <td style="text-align: right"><code>(E1 op (... op (EN-1 op EN)))</code></td>
      </tr>
      <tr>
          <td style="text-align: left"><code>(... op E)</code></td>
          <td style="text-align: right"><code>(((E1 op E2) op ...) op EN)</code></td>
      </tr>
      <tr>
          <td style="text-align: left"><code>(E op ... op I)</code></td>
          <td style="text-align: right"><code>(E1 op (... op (EN−1 op (EN op I))))</code></td>
      </tr>
      <tr>
          <td style="text-align: left"><code>(I op ... op E)</code></td>
          <td style="text-align: right"><code>((((I op E1) op E2) op ...) op EN)</code></td>
      </tr>
  </tbody>
</table>
<p>其中</p>
<ul>
<li>左折叠形式：<code>(expr op ...)</code>，其中 <code>expr</code> 是一个表达式，<code>op</code> 是二元操作符。</li>
<li>右折叠形式：<code>(... op expr)</code>，同样，<code>expr</code> 是一个表达式，<code>op</code> 是二元操作符。</li>
</ul>
<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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">T</span><span class="o">&gt;</span> <span class="c1">// variadic template
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">func2</span><span class="p">(</span><span class="n">string</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">DataStruct</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;&amp;</span><span class="p">...</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// variadic template
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">(</span><span class="n">func1</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">index</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">value</span><span class="p">),</span> <span class="p">...);</span> <span class="c1">// fold expression
</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>在上面的例子中，<code>func2</code> 函数的实现使用了右折叠表达式<code>(expr op ...)</code>。其对应关系如下：</p>
<ul>
<li><code>expr</code> : <code>func1(p, s.index, s.value)</code></li>
<li><code>op</code> : <code>, </code></li>
<li><code>...</code> : <code>...</code></li>
</ul>
<p>另一个 <code>(I op ... op E)</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Values</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">sum</span><span class="p">(</span><span class="n">Values</span> <span class="k">const</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">values</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="mi">0</span> <span class="o">+</span> <span class="p">...</span> <span class="o">+</span> <span class="n">values</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">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> <span class="c1">// same as (0 + 1 + 2 + 3 + 4)
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>其中</p>
<ul>
<li><code>I</code> : <code>0</code></li>
<li><code>op</code> : <code>+</code></li>
<li><code>...</code> : <code>...</code></li>
<li><code>op</code> : <code>+</code></li>
<li><code>E</code> : <code>values</code></li>
</ul>
<p>对于前面 <code>contX</code> 的例子，在使用 <code>C++17</code> 的 <code>Fold Expression</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">coutX</span><span class="p">(</span><span class="k">const</span> <span class="n">Types</span><span class="o">&amp;</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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">...</span> <span class="o">&lt;&lt;</span> <span class="n">args</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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>]]></content:encoded>
    </item>
    
    <item>
      <title>ChatGPT AI 协助 iOS 开发: customized sheet</title>
      <link>https://blog.tomatostore.top/posts/2023/07/swift-shared-customize-sheet/</link>
      <pubDate>Wed, 12 Jul 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/07/swift-shared-customize-sheet/</guid>
      <description>程序员走在被 OpenAI 取代的路上</description>
      <content:encoded><![CDATA[<h2 id="需求">需求</h2>
<p>App 中想加入一个订阅页面，期望 iOS 上按 bottom sheet 展示，iPad 上居中显示，同时支持横屏和竖屏，效果如下：</p>
<p><img loading="lazy" src="/images/iphone-subscription.png" alt="subscription in iPhone"  />
<img loading="lazy" src="/images/ipad-subsciption.png" alt="subscription in iPad"  /></p>
<p>iOS 15 提供了 <code>UISheetPresentationController</code> 可以令 Bottom Sheet 更方便，具体可参考<a href="https://sarunw.com/posts/bottom-sheet-in-ios-15-with-uisheetpresentationcontroller/">How to present a Bottom Sheet in iOS 15</a>还有<a href="https://www.avanderlee.com/swift/presenting-sheets-uikit-uisheetpresentationcontroller/">Presenting sheets with UIKit using a UISheetPresentationController</a>。</p>
<p><code>UISheetPresentationController</code> 不满足需求因为它只有 <code>medium</code> 和 <code>large</code> 两种高度，并且宽度是满屏，不符合需求。
通过 <code>OpenAI</code> 问答，找到了可以满足需求的方法来在一个页面中弹出订阅页面。</p>
<p>然后不出意外的，新问题又出现了：想要在另外一个页面中也弹出同样的订阅页面，当时这两个页面的父类是不同 <code>UIViewController</code>，也就是说没办法给他们定义一个共同的定制化的 <code>UIViewController</code>  子类，而 <code>Swift</code> 又不支持多继承，尝试了带默认实现的 <code>Protocol</code>，无法实现。最终还是通过询问 <code>AI</code> 找到了实现方法：</p>
<p><img loading="lazy" src="/images/chatgpt-swift-question.png" alt="dns analysis"  /></p>
<h2 id="最终实现">最终实现：</h2>
<ul>
<li><code>SubscriptionSheetPresenter.swift</code></li>
</ul>
<p>共享的 presenter</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">SubscriptionSheetPresenter</span><span class="p">:</span> <span class="n">NSObject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">static</span> <span class="kd">let</span> <span class="nv">instance</span> <span class="p">=</span> <span class="n">SubscriptionSheetPresenter</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">presentBottomSheetForSubscription</span><span class="p">(</span><span class="n">from</span> <span class="n">vc</span><span class="p">:</span> <span class="n">UIViewController</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// storyboard 中定义了定制页面的布局</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">dashboard</span> <span class="p">=</span> <span class="n">UIStoryboard</span><span class="p">.</span><span class="kd">init</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="s">&#34;Main&#34;</span><span class="p">,</span> <span class="n">bundle</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">guard</span> <span class="kd">let</span> <span class="nv">subscriptionVC</span> <span class="p">=</span> <span class="n">dashboard</span><span class="p">.</span><span class="n">instantiateViewController</span><span class="p">(</span><span class="n">withIdentifier</span><span class="p">:</span> <span class="s">&#34;subscriptionViewController&#34;</span><span class="p">)</span> <span class="k">as</span><span class="p">?</span> <span class="n">SubscriptionViewController</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">subscriptionVC</span><span class="p">.</span><span class="n">modalPresentationStyle</span> <span class="p">=</span> <span class="p">.</span><span class="n">custom</span>
</span></span><span class="line"><span class="cl">        <span class="n">subscriptionVC</span><span class="p">.</span><span class="n">transitioningDelegate</span> <span class="p">=</span> <span class="kc">self</span>
</span></span><span class="line"><span class="cl">        <span class="n">vc</span><span class="p">.</span><span class="n">present</span><span class="p">(</span><span class="n">subscriptionVC</span><span class="p">,</span> <span class="n">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="n">completion</span><span class="p">:</span> <span class="kc">nil</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// </span><span class="cs">MARK:</span><span class="c1"> - Bottom Sheet for Subscription</span>
</span></span><span class="line"><span class="cl"><span class="kd">extension</span> <span class="nc">SubscriptionSheetPresenter</span><span class="p">:</span> <span class="n">UIViewControllerTransitioningDelegate</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">presentationController</span><span class="p">(</span><span class="n">forPresented</span> <span class="n">presented</span><span class="p">:</span> <span class="n">UIViewController</span><span class="p">,</span> <span class="n">presenting</span><span class="p">:</span> <span class="n">UIViewController</span><span class="p">?,</span> <span class="n">source</span><span class="p">:</span> <span class="n">UIViewController</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="n">UIPresentationController</span><span class="p">?</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">SubscriptionSheetPresentationController</span><span class="p">(</span><span class="n">presentedViewController</span><span class="p">:</span> <span class="n">presented</span><span class="p">,</span> <span class="n">presenting</span><span class="p">:</span> <span class="n">presenting</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>SubscriptionViewController.swift</code></li>
</ul>
<p>Storyboard 中订阅页面的 UIViewController class:</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">SubscriptionViewController</span><span class="p">:</span> <span class="n">UIViewController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">@IBOutlet</span> <span class="kr">weak</span> <span class="kd">var</span> <span class="nv">monthlyBuy</span><span class="p">:</span> <span class="n">UIButton</span><span class="p">!</span>
</span></span><span class="line"><span class="cl">    <span class="kr">@IBOutlet</span> <span class="kr">weak</span> <span class="kd">var</span> <span class="nv">yearlyBuy</span><span class="p">:</span> <span class="n">UIButton</span><span class="p">!</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">override</span> <span class="kd">func</span> <span class="nf">viewWillLayoutSubviews</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">super</span><span class="p">.</span><span class="n">viewWillLayoutSubviews</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">updateUI</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="kr">override</span> <span class="kd">func</span> <span class="nf">viewWillTransition</span><span class="p">(</span><span class="n">to</span> <span class="n">size</span><span class="p">:</span> <span class="n">CGSize</span><span class="p">,</span> <span class="n">with</span> <span class="n">coordinator</span><span class="p">:</span> <span class="n">UIViewControllerTransitionCoordinator</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">super</span><span class="p">.</span><span class="n">viewWillTransition</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">size</span><span class="p">,</span> <span class="n">with</span><span class="p">:</span> <span class="n">coordinator</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">updateUI</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="kd">private</span> <span class="kd">func</span> <span class="nf">updateUI</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// update layour for diff device (iPhone/iPad) and view (Landscape/Protraint)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>SubscriptionSheetPresentationController.swift</code></li>
</ul>
<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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">SubscriptionSheetPresentationController</span><span class="p">:</span> <span class="n">UIPresentationController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">override</span> <span class="kd">var</span> <span class="nv">frameOfPresentedViewInContainerView</span><span class="p">:</span> <span class="n">CGRect</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">screenWidth</span> <span class="p">=</span> <span class="n">UIScreen</span><span class="p">.</span><span class="n">main</span><span class="p">.</span><span class="n">bounds</span><span class="p">.</span><span class="n">width</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">screenHeight</span> <span class="p">=</span> <span class="n">UIScreen</span><span class="p">.</span><span class="n">main</span><span class="p">.</span><span class="n">bounds</span><span class="p">.</span><span class="n">height</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// default is iPhone+portrait for non-SE</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nv">width</span><span class="p">:</span> <span class="n">CGFloat</span> <span class="p">=</span> <span class="n">screenWidth</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nv">height</span><span class="p">:</span> <span class="n">CGFloat</span> <span class="p">=</span> <span class="n">screenHeight</span> <span class="o">*</span> <span class="mi">2</span><span class="o">/</span><span class="mi">3</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nv">x</span><span class="p">:</span> <span class="n">CGFloat</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nv">yOffset</span> <span class="p">=</span> <span class="mf">1.0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">UIDevice</span><span class="p">.</span><span class="n">current</span><span class="p">.</span><span class="n">userInterfaceIdiom</span> <span class="p">==</span> <span class="p">.</span><span class="n">phone</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">UIDevice</span><span class="p">.</span><span class="n">current</span><span class="p">.</span><span class="n">orientation</span><span class="p">.</span><span class="n">isLandscape</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">width</span> <span class="p">=</span> <span class="n">screenWidth</span> <span class="o">/</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">                <span class="n">height</span> <span class="p">=</span> <span class="n">screenHeight</span> <span class="o">*</span> <span class="mf">0.95</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">screenHeight</span> <span class="o">&lt;</span> <span class="mi">700</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">height</span> <span class="p">=</span> <span class="n">screenHeight</span> <span class="o">*</span> <span class="mf">2.5</span><span class="o">/</span><span class="mi">3</span>
</span></span><span class="line"><span class="cl">                <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="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// iPad or Mac</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">UIDevice</span><span class="p">.</span><span class="n">current</span><span class="p">.</span><span class="n">orientation</span><span class="p">.</span><span class="n">isLandscape</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">width</span> <span class="p">=</span> <span class="n">screenWidth</span> <span class="o">/</span> <span class="mf">2.5</span>
</span></span><span class="line"><span class="cl">                <span class="n">height</span> <span class="p">=</span> <span class="n">screenHeight</span> <span class="o">*</span> <span class="mf">0.65</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">width</span> <span class="p">=</span> <span class="n">screenWidth</span> <span class="o">/</span> <span class="mf">1.8</span>
</span></span><span class="line"><span class="cl">                <span class="n">height</span> <span class="p">=</span> <span class="n">screenHeight</span> <span class="o">*</span> <span class="mf">0.5</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="n">yOffset</span> <span class="p">=</span> <span class="mf">0.5</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="n">x</span> <span class="p">=</span> <span class="p">(</span><span class="n">screenWidth</span> <span class="o">-</span> <span class="n">width</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">CGRect</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                      <span class="n">y</span><span class="p">:</span> <span class="p">(</span><span class="n">containerView</span><span class="p">.</span><span class="n">bounds</span><span class="p">.</span><span class="n">height</span> <span class="o">-</span> <span class="n">height</span><span class="p">)</span> <span class="o">*</span> <span class="n">yOffset</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                      <span class="n">width</span><span class="p">:</span> <span class="n">width</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                      <span class="n">height</span><span class="p">:</span> <span class="n">height</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="kr">override</span> <span class="kd">func</span> <span class="nf">containerViewWillLayoutSubviews</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">super</span><span class="p">.</span><span class="n">containerViewWillLayoutSubviews</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="kd">let</span> <span class="nv">presentedView</span> <span class="p">=</span> <span class="n">presentedView</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">presentedView</span><span class="p">.</span><span class="n">frame</span> <span class="p">=</span> <span class="n">frameOfPresentedViewInContainerView</span>
</span></span><span class="line"><span class="cl">        <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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>在需要弹出订阅页面的 <code>UIViewController</code> 中直接调用即可：</p>
<ul>
<li><code>&lt;Any&gt;ViewController.swift</code></li>
</ul>
<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-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="p">&lt;</span><span class="nb">Any</span><span class="p">&gt;</span><span class="n">ViewController</span><span class="p">:</span> <span class="p">&lt;</span><span class="n">XXX</span><span class="p">&gt;</span><span class="n">ViewController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">showSubscription</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">SubscriptionSheetPresenter</span><span class="p">.</span><span class="n">instance</span><span class="p">.</span><span class="n">presentBottomSheetForSubscription</span><span class="p">(</span><span class="n">from</span><span class="p">:</span> <span class="kc">self</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>&lt;Another&gt;ViewController.swift</code></li>
</ul>
<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-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="p">&lt;</span><span class="n">Anyother</span><span class="p">&gt;</span><span class="n">ViewController</span><span class="p">:</span> <span class="p">&lt;</span><span class="n">YYY</span><span class="p">&gt;</span><span class="n">ViewController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">goPremium</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">SubscriptionSheetPresenter</span><span class="p">.</span><span class="n">instance</span><span class="p">.</span><span class="n">presentBottomSheetForSubscription</span><span class="p">(</span><span class="n">from</span><span class="p">:</span> <span class="kc">self</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="usefull-links">Usefull links</h2>
<ul>
<li><a href="https://blog.tomatostore.top/posts/2023/04/swift-block-based-animation/">Swift: beginAnimations(_:context:) was deprecated in iOS 13.0: Use the block-based animation API instead
</a></li>
<li><a href="https://blog.tomatostore.top/posts/2023/04/swift-substring/">Swift String Substring
</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>C&#43;&#43; template&lt;class&gt; v.s. template&lt;typename&gt;</title>
      <link>https://blog.tomatostore.top/posts/2023/06/cpp-template-parameter-class-vs-typename/</link>
      <pubDate>Wed, 21 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/06/cpp-template-parameter-class-vs-typename/</guid>
      <description>C&#43;&#43;模板用typename和class有啥区别</description>
      <content:encoded><![CDATA[<p><strong>Q:</strong> <code>C++</code> 模板用 <code>typename</code> 和 <code>class</code> 有啥区别?
<strong>A:</strong> 无论使用 <code>class</code> 还是 <code>typename</code> 声明类型参数，效果都是相同的，选择使用哪个关键字主要取决于个人或团队的偏好。一般来说，较为常见的做法是在声明类模板时使用 class，而在嵌套类型的声明或模板内部使用时则使用 typename。</p>
<hr>
<p>早期的 <code>C++</code> 标准将 <code>class</code> 用作声明类型参数的关键字。为了支持<em>模板内嵌套类型</em>，<code>C++98</code> 标准引入了 <code>typename</code>， 同时为了兼容性，<code>class</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// template&lt;class&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyClass1</span> <span class="p">{</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// template&lt;typename&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyContainer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// internal usage
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">using</span> <span class="n">value_type</span> <span class="o">=</span> <span class="n">T</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// nested type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">typename</span> <span class="n">MyContainer</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">value_type</span> <span class="n">getValue</span><span class="p">()</span> <span class="p">{</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="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>如何选择正确的日志级别（log level）</title>
      <link>https://blog.tomatostore.top/posts/2023/06/loglevel-introduction/</link>
      <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/06/loglevel-introduction/</guid>
      <description>Log Level Introduction</description>
      <content:encoded><![CDATA[<h2 id="日志级别的历史">日志级别的历史：</h2>
<p><code>日志级别（log level）</code>起源于 20 世纪 80 年代的由 <code>Eric Allman</code> 开发的项目 <code>Sendmail</code> 。该项目需要一种日志记录解决方案，这最终导致了 <code>System Logging Protocol（Syslog）</code> 的创建以及不同日志级别的概念。后来 <code>Syslog</code> 被广泛应用于各种应用程序，并成为系统日志和事件消息的标准协议。</p>
<h2 id="日志级别">日志级别</h2>
<p>按重要性递减排列：</p>
<ul>
<li>OFF：不记录任何日志信息。</li>
<li>FATAL：表示应用程序即将发生严重问题或数据损坏，意味着应用程序处于灾难性状态，重要功能无法正常工作。</li>
<li>ERROR：表示无法访问服务或文件等重要故障，应用程序可能继续运行，但需要及时处理。</li>
<li>WARN：表示检测到意外问题，可能会影响特定进程的运行，但不会对应用程序造成损害。</li>
<li>INFO：记录应用程序的正常行为，如服务启动或停止、数据库添加等，通常不需要跟进处理。</li>
<li>DEBUG：提供详细的诊断信息，用于故障诊断、排查或测试应用程序。</li>
<li>TRACE：捕获应用程序行为的详细信息，比DEBUG级别更细粒度，用于查看代码中的参数或解释算法的步骤。</li>
<li>ALL：记录所有定义的日志级别，包括自定义日志级别，相当于综合所有级别的日志。</li>
</ul>
<h2 id="常用日志库">常用日志库</h2>
<table>
  <thead>
      <tr>
          <th>编程语言</th>
          <th>日志库</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>C++</td>
          <td><a href="https://github.com/gabime/spdlog">spdlog</a>, <a href="https://www.boost.org/doc/libs/1_75_0/libs/log/doc/html/index.html">Boost.Log</a></td>
      </tr>
      <tr>
          <td>Java</td>
          <td><a href="https://logging.apache.org/log4j/2.x/">Log4j</a>, <a href="http://www.slf4j.org/">Slf4j</a></td>
      </tr>
      <tr>
          <td>Python</td>
          <td><a href="https://docs.python.org/3/library/logging.html">Python logging</a>, <a href="https://github.com/Delgan/loguru">Loguru</a></td>
      </tr>
      <tr>
          <td>JavaScript</td>
          <td><a href="https://github.com/winstonjs/winston">Winston</a>, <a href="https://github.com/trentm/node-bunyan">Bunyan</a></td>
      </tr>
      <tr>
          <td>C#</td>
          <td><a href="https://nlog-project.org/">NLog</a>, <a href="https://serilog.net/">Serilog</a></td>
      </tr>
      <tr>
          <td>Go</td>
          <td><a href="https://github.com/sirupsen/logrus">logrus</a>, <a href="https://github.com/uber-go/zap">zap</a></td>
      </tr>
      <tr>
          <td>Ruby</td>
          <td><a href="https://github.com/colbygk/log4r">Log4r</a>, <a href="https://ruby-doc.org/stdlib-3.0.2/libdoc/logger/rdoc/Logger.html">Logger</a></td>
      </tr>
      <tr>
          <td>PHP</td>
          <td><a href="https://github.com/Seldaek/monolog">Monolog</a>, <a href="https://laravel.com/docs/8.x/logging">Laravel Log</a></td>
      </tr>
  </tbody>
</table>
]]></content:encoded>
    </item>
    
    <item>
      <title>Use customized class in std::map, std::set</title>
      <link>https://blog.tomatostore.top/posts/2023/05/custom-class-with-std-associative-container/</link>
      <pubDate>Fri, 19 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/05/custom-class-with-std-associative-container/</guid>
      <description>Make self-defined class comparable</description>
      <content:encoded><![CDATA[<p>有一个自定义的 <code>class A</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">A</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">  <span class="o">~</span><span class="n">A</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="kt">int</span> <span class="nf">getVal</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">val</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">setVal</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="n">val</span> <span class="o">=</span> <span class="n">i</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="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">val</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>当尝试把 class A 的对象存到 std::set 或作为key用在 std:map 中时，会有编译错误。</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;set&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</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="n">A</span> <span class="n">a1</span><span class="p">,</span> <span class="n">a2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">a1</span><span class="p">.</span><span class="n">setVal</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="n">a2</span><span class="p">.</span><span class="n">setVal</span><span class="p">(</span><span class="o">-</span><span class="mi">200</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">map</span><span class="o">&lt;</span><span class="n">A</span><span class="p">,</span> <span class="n">string</span><span class="o">&gt;</span> <span class="n">mapOfA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">mapOfA</span><span class="p">[</span><span class="n">a1</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;hello&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">mapOfA</span><span class="p">[</span><span class="n">a2</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;world&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">set</span><span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="n">setOfA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">setOfA</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">a1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="n">setOfA</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">a2</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>compile error:</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-shell" data-lang="shell"><span class="line"><span class="cl">/usr/include/c++/9/bits/stl_function.h: In instantiation of ‘constexpr bool std::less&lt;_Tp&gt;::operator<span class="o">()(</span>const _Tp<span class="p">&amp;</span>, const _Tp<span class="p">&amp;</span><span class="o">)</span> const <span class="o">[</span>with <span class="nv">_Tp</span> <span class="o">=</span> A<span class="o">]</span>’:
</span></span><span class="line"><span class="cl">/usr/include/c++/9/bits/stl_map.h:497:32:   required from ‘std::map&lt;_Key, _Tp, _Compare, _Alloc&gt;::mapped_type<span class="p">&amp;</span> std::map&lt;_Key, _Tp, _Compare, _Alloc&gt;::operator<span class="o">[](</span>const key_type<span class="p">&amp;</span><span class="o">)</span> <span class="o">[</span>with <span class="nv">_Key</span> <span class="o">=</span> A<span class="p">;</span> <span class="nv">_Tp</span> <span class="o">=</span> std::__cxx11::basic_string&lt;char&gt;<span class="p">;</span> <span class="nv">_Compare</span> <span class="o">=</span> std::less&lt;A&gt;<span class="p">;</span> <span class="nv">_Alloc</span> <span class="o">=</span> std::allocator&lt;std::pair&lt;const A, std::__cxx11::basic_string&lt;char&gt; &gt; &gt;<span class="p">;</span> std::map&lt;_Key, _Tp, _Compare, _Alloc&gt;::mapped_type <span class="o">=</span> std::__cxx11::basic_string&lt;char&gt;<span class="p">;</span> std::map&lt;_Key, _Tp, _Compare, _Alloc&gt;::key_type <span class="o">=</span> A<span class="o">]</span>’
</span></span><span class="line"><span class="cl">/home/rduis/Workspace/github/notesnotes/swift/src/custom-class-in-std-map.cpp:25:12:   required from here
</span></span><span class="line"><span class="cl">/usr/include/c++/9/bits/stl_function.h:386:20: error: no match <span class="k">for</span> ‘operator&lt;’ <span class="o">(</span>operand types are ‘const A’ and ‘const A’<span class="o">)</span>
</span></span><span class="line"><span class="cl">  <span class="m">386</span> <span class="p">|</span>       <span class="o">{</span> <span class="k">return</span> __x &lt; __y<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>                ~~~~^~~~~
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="solution-1">solution 1:</h2>
<p>declare <code>operator &lt; </code> in class A:</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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">A</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">  <span class="o">~</span><span class="n">A</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="kt">int</span> <span class="nf">getVal</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">val</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">setVal</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="n">val</span> <span class="o">=</span> <span class="n">i</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">// solution 1: operator &lt;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kt">bool</span> <span class="k">operator</span><span class="o">&lt;</span><span class="p">(</span><span class="k">const</span> <span class="n">A</span> <span class="o">&amp;</span><span class="n">rhs</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">val</span> <span class="o">&lt;</span> <span class="n">rhs</span><span class="p">.</span><span class="n">getVal</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="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">val</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><h2 id="solution-2">solution 2:</h2>
<ol>
<li>create a new class as comparator</li>
<li>modify map declaration:</li>
</ol>
<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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">A</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">  <span class="o">~</span><span class="n">A</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="kt">int</span> <span class="nf">getVal</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">val</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">setVal</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="n">val</span> <span class="o">=</span> <span class="n">i</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="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">val</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="c1">// solution 2: delcare comparator
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">comparator</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">A</span><span class="o">&amp;</span> <span class="n">lhs</span><span class="p">,</span> <span class="k">const</span> <span class="n">A</span><span class="o">&amp;</span> <span class="n">rhs</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">lhs</span><span class="p">.</span><span class="n">getVal</span><span class="p">()</span> <span class="o">&lt;</span> <span class="n">rhs</span><span class="p">.</span><span class="n">getVal</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="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="why">Why</h2>
<ul>
<li>
<p><code>std::map</code> and <code>std::set</code> are <strong>sorted</strong> associative containers.</p>
</li>
<li>
<p>Sorting is done using the <strong>comparison function Compare</strong>.</p>
</li>
<li>
<p>Declaration of <code>std::map</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">    <span class="k">class</span> <span class="nc">Key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">class</span> <span class="nc">T</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">class</span> <span class="nc">Compare</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">less</span><span class="o">&lt;</span><span class="n">Key</span><span class="o">&gt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">class</span> <span class="nc">Allocator</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">pair</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Key</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="k">class</span> <span class="nc">map</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>Declaration of <code>std::map</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">Key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">Compare</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">less</span><span class="o">&lt;</span><span class="n">Key</span><span class="o">&gt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">Allocator</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="n">Key</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="k">class</span> <span class="nc">set</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h2 id="ref">Ref</h2>
<ul>
<li><a href="https://en.cppreference.com/w/cpp/container/map">https://en.cppreference.com/w/cpp/container/map</a></li>
<li><a href="https://stackoverflow.com/questions/1102392/how-can-i-use-stdmaps-with-user-defined-types-as-key">https://stackoverflow.com/questions/1102392/how-can-i-use-stdmaps-with-user-defined-types-as-key</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>[C&#43;&#43;11] Scoped Enumeration (enum class)</title>
      <link>https://blog.tomatostore.top/posts/2023/05/cpp-scoped-enum-class/</link>
      <pubDate>Thu, 18 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/05/cpp-scoped-enum-class/</guid>
      <description>Strong typed enums in C&#43;&#43;11</description>
      <content:encoded><![CDATA[<h2 id="traditional-enum-in-c">Traditional enum in C++</h2>
<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-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Week</span>        <span class="p">{</span><span class="n">Mon</span>   <span class="p">,</span><span class="n">Tue</span>   <span class="p">,</span><span class="n">Wed</span>  <span class="p">,</span><span class="n">Thu</span>  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Season</span>      <span class="p">{</span><span class="n">Sprint</span><span class="p">,</span><span class="n">Summer</span><span class="p">,</span><span class="n">Fall</span> <span class="p">,</span><span class="n">Winter</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Week</span> <span class="n">w</span> <span class="o">=</span> <span class="n">Tue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">Season</span> <span class="n">s</span> <span class="o">=</span> <span class="n">Summer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="n">isEqual</span> <span class="o">=</span> <span class="p">(</span><span class="n">w</span> <span class="o">==</span> <span class="n">s</span><span class="p">);</span> <span class="c1">// isEqual is true
</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><h3 id="problem">Problem</h3>
<p>非类型安全，比如对<code>Week w</code>和<code>Season s</code>两个逻辑意义上不同类型的变量作比较，会产生不合逻辑的结果：<code>w == s</code> 是 <code>true</code>。</p>
<p>It&rsquo;s not safe, the result of <code>w == s</code> is <code>true</code> is not reasonalbe.</p>
<p>不同类型的 enum 比较会有编译警告<code>warning</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">warning: comparison between ‘enum Week’ and ‘enum Season’ <span class="o">[</span>-Wenum-compare<span class="o">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>   bool <span class="nv">isEqual</span> <span class="o">=</span> <span class="o">(</span><span class="nv">w</span> <span class="o">==</span> s<span class="o">)</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><h2 id="scoped-enum">Scoped enum</h2>
<ul>
<li><code>enum class</code> and <code>enum struct</code> are the same</li>
<li><code>enum class</code> is not a class</li>
</ul>
<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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">EnumOnly</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Week</span> <span class="p">{</span> <span class="n">Mon</span><span class="p">,</span> <span class="n">Tue</span><span class="p">,</span> <span class="n">Wed</span><span class="p">,</span> <span class="n">Thu</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Season</span> <span class="p">{</span> <span class="n">Sprint</span><span class="p">,</span> <span class="n">Summer</span><span class="p">,</span> <span class="n">Fall</span><span class="p">,</span> <span class="n">Winter</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="c1">// namespace EnumOnly
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">EnumClass</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Month</span> <span class="p">{</span> <span class="n">Jan</span><span class="p">,</span> <span class="n">Feb</span><span class="p">,</span> <span class="n">Mar</span><span class="p">,</span> <span class="n">Apr</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Num</span> <span class="p">{</span> <span class="n">One</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">Two</span><span class="p">,</span> <span class="n">Three</span><span class="p">,</span> <span class="n">Four</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="c1">// namespace EnumClass
</span></span></span><span class="line"><span class="cl"><span class="c1"></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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;EnumOnly::Week::Mon = &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">EnumOnly</span><span class="o">::</span><span class="n">Week</span><span class="o">::</span><span class="n">Mon</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;EnumClass::Month::Jan = &#34;</span> <span class="o">&lt;&lt;</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">EnumClass</span><span class="o">::</span><span class="n">Month</span><span class="o">::</span><span class="n">Jan</span><span class="p">)</span> <span class="o">&lt;&lt;</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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Is EnumOnly::Week a class : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">is_class</span><span class="o">&lt;</span><span class="n">EnumOnly</span><span class="o">::</span><span class="n">Week</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Is EnumOnly::Week a enum : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">is_enum</span><span class="o">&lt;</span><span class="n">EnumOnly</span><span class="o">::</span><span class="n">Week</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">&lt;&lt;</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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Is EnumClass::Month a class : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">is_class</span><span class="o">&lt;</span><span class="n">EnumClass</span><span class="o">::</span><span class="n">Month</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Is EnumClass::Month a enum : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">is_enum</span><span class="o">&lt;</span><span class="n">EnumClass</span><span class="o">::</span><span class="n">Month</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">&lt;&lt;</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></span><span class="line"><span class="cl">  <span class="n">EnumOnly</span><span class="o">::</span><span class="n">Week</span> <span class="n">w</span> <span class="o">=</span> <span class="n">EnumOnly</span><span class="o">::</span><span class="n">Tue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">EnumOnly</span><span class="o">::</span><span class="n">Season</span> <span class="n">s</span> <span class="o">=</span> <span class="n">EnumOnly</span><span class="o">::</span><span class="n">Summer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">EnumClass</span><span class="o">::</span><span class="n">Month</span> <span class="n">m</span> <span class="o">=</span> <span class="n">EnumClass</span><span class="o">::</span><span class="n">Month</span><span class="o">::</span><span class="n">Feb</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span> <span class="n">n</span> <span class="o">=</span> <span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span><span class="o">::</span><span class="n">Two</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span> <span class="n">n2</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span> <span class="n">n3</span> <span class="o">=</span> <span class="n">EnumClass</span><span class="o">::</span><span class="n">Num</span><span class="o">::</span><span class="n">Three</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">w</span> <span class="o">==</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;w == s, ohh!&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>  <span class="c1">// unmeaningful
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;w != s&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="n">n2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;n == n2, yes&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;n != n2, why&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="n">n3</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;n == n3&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;n != n3, yes&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">  if (w == m) {
</span></span></span><span class="line"><span class="cl"><span class="cm">    cout &lt;&lt; &#34;w == m&#34;;
</span></span></span><span class="line"><span class="cl"><span class="cm">  } else {
</span></span></span><span class="line"><span class="cl"><span class="cm">    cout &lt;&lt; &#34;w != m&#34;;
</span></span></span><span class="line"><span class="cl"><span class="cm">  }
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">EnumOnly::Week::Mon <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">EnumClass::Month::Jan <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">Is EnumOnly::Week a class : <span class="m">0</span>
</span></span><span class="line"><span class="cl">Is EnumOnly::Week a enum : <span class="m">1</span>
</span></span><span class="line"><span class="cl">Is EnumClass::Month a class : <span class="m">0</span>
</span></span><span class="line"><span class="cl">Is EnumClass::Month a enum : <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="nv">w</span> <span class="o">==</span> s, ohh!
</span></span><span class="line"><span class="cl"><span class="nv">n</span> <span class="o">==</span> n2, yes
</span></span><span class="line"><span class="cl">n !<span class="o">=</span> n3, yes
</span></span></code></pre></td></tr></table>
</div>
</div><p>如果用 <code>==</code> 比较两个不同类型的 <code>enum class</code> 对象会产生编译错误。
比如用<code>if (w == m)</code>比较 <code>enum Week</code> 类型的 <code>w</code> 与 <code>enum class Month</code> 类型的 <code>m</code> 会产生如下错误 <code>error</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">error: no match <span class="k">for</span> ‘operator<span class="o">==</span>’ <span class="o">(</span>operand types are ‘EnumOnly::Week’ and ‘EnumClass::Month’<span class="o">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>   <span class="k">if</span> <span class="o">(</span><span class="nv">w</span> <span class="o">==</span> m<span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>       ~ ^~ ~
</span></span><span class="line"><span class="cl">      <span class="p">|</span>       <span class="p">|</span>    <span class="p">|</span>
</span></span><span class="line"><span class="cl">      <span class="p">|</span>       <span class="p">|</span>    EnumClass::Month
</span></span><span class="line"><span class="cl">      <span class="p">|</span>       EnumOnly::Week
</span></span></code></pre></td></tr></table>
</div>
</div><p>用 <code>==</code> 比较两个不同的 <code>enum class</code> 对象也会产生相同的编译错误。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>error: git object file .git/objects/xxx is empty 和 fatal: cannot read existing object info</title>
      <link>https://blog.tomatostore.top/posts/2023/04/git-object-file-is-empty/</link>
      <pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/git-object-file-is-empty/</guid>
      <description>index-pack failed，unable to unlink null bad address</description>
      <content:encoded><![CDATA[<h2 id="object-file-相关错误"><code>object file</code> 相关错误</h2>
<p>本地的<code>repo</code>在执行<code>git log</code>和<code>git pull</code>命令时出现了如下关于<code>object file</code>的错误：</p>
<h3 id="git-log-错误"><code>git log</code> 错误</h3>
<pre tabindex="0"><code>&gt;&gt;&gt;&gt; $ git log
error: object file .git/objects/7b/40exxx is empty
error: object file .git/objects/7b/40exxx is empty
fatal: loose object 7b40exxx (stored in .git/objects/7b/40exxx) is corrupt
</code></pre><h3 id="git-pull-错误"><code>git pull</code> 错误</h3>
<pre tabindex="0"><code>&gt;&gt;&gt;&gt; $ git pull
error: object file .git/objects/7b/40exxx is empty
error: object file .git/objects/7b/40exxx is empty
remote: Counting objects: 479, done
remote: Finding sources: 100% (1388/1388)
error: object file .git/objects/7b/40exxx is empty
fatal: cannot read existing object info 40exxx
fatal: index-pack failed
warning: unable to unlink &#39;(null)&#39;: Bad address
</code></pre><h2 id="解决方法-solution">解决方法 Solution</h2>
<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-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> &lt;your_repo&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 备份 .git</span>
</span></span><span class="line"><span class="cl">cp -r .git .git-bak
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> .git
</span></span><span class="line"><span class="cl">find . -type f -empty -delete -print
</span></span><span class="line"><span class="cl">git fsck --full
</span></span></code></pre></td></tr></table>
</div>
</div><p>再次尝试<code>git log</code> 和 <code>git pull</code>命令。一切正常后删除备份 <code>rm -r .git-bak</code>。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>如何从 App Store Connect 中删除一个未发布版本</title>
      <link>https://blog.tomatostore.top/posts/2023/04/app-store-connect-rm-a-version/</link>
      <pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/app-store-connect-rm-a-version/</guid>
      <description>苹果商店Connect无法删除App版本</description>
      <content:encoded><![CDATA[<p>一个 iOS App 最新已发布版本: <code>4.0</code>，在 <code>App Store Connect</code> 中添加了一个版本 <code>4.1</code>，状态为 <code>准备提交（Prepare for Submission）</code> (或其他未发布状态)。</p>
<p>后来改动有点大，打算做个大版本升级——把<code>4.1</code> 改为 <code>5.0</code>。</p>
<p>没有找到删除 <code>4.1</code> 的方法，但是可以通过如下途径更改版本为 <code>5.0</code>:</p>
<p>在 <code>version 4.1</code> 构建页面的 版本信息（Version Information） 模块下将版本 <code>4.1</code> 直接改为 <code>5.0</code>:</p>
<p><img loading="lazy" src="/images/v4.1.png" alt="v5.0"  /></p>
<p>点击 保存（Save）按钮，版本 <code>4.1</code> 就变成 <code>5.0</code> 啦：</p>
<p><img loading="lazy" src="/images/v5.0.png" alt="v5.0"  /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>如何在 Markdown 中插入图片，并设置大小</title>
      <link>https://blog.tomatostore.top/posts/2023/04/markdown-insert-picture-with-size/</link>
      <pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/markdown-insert-picture-with-size/</guid>
      <description>Add pictures to Markdown, with hyperlink and size setting</description>
      <content:encoded><![CDATA[<p>本文介绍在 <code>Markdown</code> 文件中插入图片的两种方式：<a href="#markdown_insert_img">1.Markdown语法</a>，<a href="#html_insert_img">2.HTML语法</a>；
以及<a href="#image_size">如何设置图片尺寸</a>，<a href="#image_link">如何给图片加链接</a>。</p>
<p><a name="markdown_insert_img"></a></p>
<h2 id="1-使用-markdown-语法">1. 使用 <code>Markdown</code> 语法</h2>
<ul>
<li>以叹号<code>!</code>开头</li>
<li>后面方括号<code>[]</code>中是替换文本（图片加载失败时显示给读者的文本）</li>
<li>再后面圆括号<code>()</code>中是图片的路径（本地路径、网络路径）</li>
<li>如果需要图片标题，可以在路径后面用双引号<code>&quot;&quot;</code>扩起来。
<em>⚠️：所有的<strong>符号必须是半角/英文符号</strong>，不可以使用全角/中文符号</em></li>
</ul>
<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-markdown" data-lang="markdown"><span class="line"><span class="cl">![<span class="nt">替换文本</span>](<span class="na">图片路径 &#34;图片标题&#34;</span>)
</span></span><span class="line"><span class="cl">![<span class="nt">alt text</span>](<span class="na">image_path &#34;image title&#34;</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">![<span class="nt">substring is deprecated</span>](<span class="na">/images/xcode-while-editing.png &#34;XCode屏幕截图&#34;</span>)
</span></span><span class="line"><span class="cl"><span class="ge">*Tips: 可以在图片下面用一行斜体的说明文本。图片标题不保证一定会显示*</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>显示效果如下：
<img loading="lazy" src="/images/xcode-while-editing.png" alt="substring is deprecated"  title="XCode屏幕截图"  />
<em>Tips: 可以在图片下面用一行斜体的说明文本。图片标题不保证一定会显示</em></p>
<p><a name="html_insert_img"></a></p>
<h2 id="2-使用-html-语法">2. 使用 <code>HTML</code> 语法</h2>
<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-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">image</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://picsum.photos/400/200&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;网络图片400*200&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>效果如下：
<image src="https://picsum.photos/400/200" alt="网络图片400*200" title="HTML图片"></p>
<p><a name="image_size"></a></p>
<h3 id="如何设置图片尺寸">如何设置图片尺寸</h3>
<p>推荐使用<code>HTML</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">image</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://picsum.photos/400/200&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;网络图片400*200&#34;</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;100&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;200&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><image src="https://picsum.photos/400/200" alt="网络图片400*200" width="100" height="200">
<p>原生<code>Markdown</code>语法不支持设置图片尺寸，<code>Extended Markdown</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">![<span class="nt">alt text</span>](<span class="na">image path &#34;image title&#34;</span>){ width=80%,height=120px }
</span></span></code></pre></td></tr></table>
</div>
</div><a name="image_link" />
<h3 id="如何给图片加链接">如何给图片加链接</h3>
<h4 id="markdown语法"><code>Markdown</code>语法</h4>
<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-markdown" data-lang="markdown"><span class="line"><span class="cl">[<span class="nt">![图片替换文本</span>](<span class="na">图片路径</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-markdown" data-lang="markdown"><span class="line"><span class="cl">[<span class="nt">![点击图片跳转AppStore</span>](<span class="na">https://mzstatic.com/image/AppIcon.png</span>)](https://apps.apple.com)
</span></span></code></pre></td></tr></table>
</div>
</div><p><a href="https://apps.apple.com/cn/app/id1528477391">
  <img loading="lazy" src="https://is4-ssl.mzstatic.com/image/thumb/Purple122/v4/72/62/8a/72628ae2-9c11-e676-acb2-5e207f07aa65/AppIcon-1x_U007emarketing-0-6-0-85-220.png/460x0w.webp" alt="点击图片跳转AppStore"  /></a></p>
<h4 id="html语法"><code>HTML</code>语法</h4>
<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-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://apps.apple.com/cn/app/id1528477391&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://mzstatic.com/image/AppIcon.png&#34;</span><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><a href="https://apps.apple.com/cn/app/id1528477391">
    <img src="https://is4-ssl.mzstatic.com/image/thumb/Purple122/v4/72/62/8a/72628ae2-9c11-e676-acb2-5e207f07aa65/AppIcon-1x_U007emarketing-0-6-0-85-220.png/460x0w.webp" />
</a>
]]></content:encoded>
    </item>
    
    <item>
      <title>Bad owner or permissions on ssh config/git命令.ssh文件权限错误</title>
      <link>https://blog.tomatostore.top/posts/2023/04/ssh-file-permission/</link>
      <pubDate>Mon, 17 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/ssh-file-permission/</guid>
      <description>ssh Permissions are too open</description>
      <content:encoded><![CDATA[<p>在 macOS 的终端中执行 <code>git pull</code> 命令时出现如下两个错误，可以通过手动修改权限来修复。同样适用于 Linux 系统及其他 ssh 相关应用出现的此类错误。</p>
<ul>
<li>错误一：</li>
</ul>
<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-text" data-lang="text"><span class="line"><span class="cl">Bad owner or permissions on &lt;user&gt;/.ssh/config
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>错误二：</li>
</ul>
<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-text" data-lang="text"><span class="line"><span class="cl">@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
</span></span><span class="line"><span class="cl">@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
</span></span><span class="line"><span class="cl">@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
</span></span><span class="line"><span class="cl">Permissions 0640 for &#39;&lt;user&gt;/.ssh/id_rsa&#39; are too open.
</span></span><span class="line"><span class="cl">It is required that your private key files are NOT accessible by others.
</span></span><span class="line"><span class="cl">This private key will be ignored.
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="solution">Solution</h2>
<p>通过如下方式手动修复 <code>.ssh</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> ~/.ssh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo chmod <span class="m">700</span> .      <span class="c1"># .ssh dir</span>
</span></span><span class="line"><span class="cl">sudo chmod <span class="m">700</span> *.pub  <span class="c1"># PUBLIC key file</span>
</span></span><span class="line"><span class="cl">sudo chmod <span class="m">600</span> id_rsa <span class="c1"># PRIVATE key file</span>
</span></span><span class="line"><span class="cl">sudo chmod <span class="m">600</span> config <span class="c1"># config file</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="reference">Reference</h2>
<p>其他类型文件的权限及详细描述参见 <code>man ssh</code>：</p>
<p><img loading="lazy" src="/images/man-ssh.png" alt="man ssh"  /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swift String Substring</title>
      <link>https://blog.tomatostore.top/posts/2023/04/swift-substring/</link>
      <pubDate>Sun, 16 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/swift-substring/</guid>
      <description>&lt;p&gt;Swift 中对 &lt;code&gt;String&lt;/code&gt; 类型的 &lt;code&gt;substring()&lt;/code&gt; 方法都被标记为&lt;code&gt;不推荐(deprecated)&lt;/code&gt;了，那该如何实现 substring 的功能呢？&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://blog.tomatostore.top/images/swift-string-substring-deprecated.jpg&#34; alt=&#34;substring is deprecated&#34;  title=&#34;XCode 中对String.substring的提示&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;根据Xcode的提示&lt;strong&gt;可以使用&lt;code&gt;slicing（切片）&lt;/code&gt;的方式来实现&lt;code&gt;substring&lt;/code&gt;的功能&lt;/strong&gt;：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Swift 中对 <code>String</code> 类型的 <code>substring()</code> 方法都被标记为<code>不推荐(deprecated)</code>了，那该如何实现 substring 的功能呢？</p>
<p><img loading="lazy" src="/images/swift-string-substring-deprecated.jpg" alt="substring is deprecated"  title="XCode 中对String.substring的提示"  /></p>
<p>根据Xcode的提示<strong>可以使用<code>slicing（切片）</code>的方式来实现<code>substring</code>的功能</strong>：</p>
<p>以字符串 <code>let str = &quot;0123456789&quot;</code> 为例:</p>
<h3 id="从开始到第一个等于5的字符之前的子串">从开始到第一个等于<code>5</code>的字符之前的子串：</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-swift" data-lang="swift"><span class="line"><span class="cl"><span class="k">if</span> <span class="kd">let</span> <span class="nv">firstFive</span> <span class="p">=</span> <span class="n">str</span><span class="p">.</span><span class="n">firstIndex</span><span class="p">(</span><span class="n">of</span><span class="p">:</span> <span class="s">&#34;5&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">substr</span> <span class="p">=</span> <span class="n">str</span><span class="p">[</span><span class="n">str</span><span class="p">.</span><span class="n">startIndex</span><span class="p">..&lt;</span><span class="n">firstFive</span><span class="p">]</span> <span class="c1">// substr = 01234</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 或者可以省略开始的index</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nv">substr2</span> <span class="p">=</span> <span class="n">str</span><span class="p">[..&lt;</span><span class="n">firstFive</span><span class="p">]</span> <span class="c1">// substr2 = 01234</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="从开头到第一个等于5的字符">从开头到第一个等于<code>5</code>的字符</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">substr</span> <span class="p">=</span> <span class="n">str</span><span class="p">[...</span><span class="n">firstFive</span><span class="p">]</span> <span class="c1">// substr = 012345</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="从第一个5开始到字符串末尾">从第一个<code>5</code>开始到字符串末尾</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">substr</span> <span class="p">=</span> <span class="n">str</span><span class="p">[</span><span class="n">firstFive</span><span class="p">...]</span> <span class="c1">// 56789</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="前7个字符">前7个字符</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">strstr</span> <span class="p">=</span> <span class="n">str</span><span class="p">[</span><span class="n">str</span><span class="p">.</span><span class="n">startIndex</span><span class="p">..&lt;</span><span class="n">str</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">startIndex</span><span class="p">,</span> <span class="n">offsetBy</span><span class="p">:</span> <span class="mi">7</span><span class="p">)]</span> <span class="c1">// 0123456</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>String</code>切片后返回的结果类型是 <code>Substring</code>。</p>
<h2 id="struct-substring">struct Substring</h2>
<p><code>Substring</code> 不会为字符串额外分配空间，而是与原始字符串共享存储。</p>
<blockquote>
<p><strong>划重点：</strong> 因为<code>Substring</code>会持有对原始字符存储的引用计数，所以要确保子串的生命周期不长于源字符串的生命周期，以免内存泄漏。</p></blockquote>
<hr>
<blockquote>
<p>Ref: <a href="https://swiftunboxed.com/stdlib/substrings">https://swiftunboxed.com/stdlib/substrings</a></p></blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>关于ASCII、DBCS、Unicode、UCS-16、UTF-8和Encoding</title>
      <link>https://blog.tomatostore.top/posts/2023/04/unicode-and-character-sets/</link>
      <pubDate>Wed, 12 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/unicode-and-character-sets/</guid>
      <description>每个程序员都应该知道的字符集发展简史</description>
      <content:encoded><![CDATA[<p>写于二十年前(<code>2003年</code>)的文章，现在依然受用。</p>
<p>你是否曾探究过<code>HTTP</code>请求中神秘的<code>Content-Type</code>？你是否曾遇到过满是问号 <code>???? ???? ??</code> 的电子邮件（或网页）？</p>
<p>作者发现多数程序开发人员并不是完全明白字符集<code>character set</code>、编码<code>encoding</code>、<code>Unicode</code>、<code>UTF-8</code>等相关话题。</p>
<p>这篇文章回顾了字符集的发展历史。</p>
<p><img loading="lazy" src="/images/ascii.png" alt="ASCII"  /></p>
<h2 id="asciiamerican-standard-code-for-information-interchange美国信息交换标准代码"><code>ASCII</code>（<code>American Standard Code for Information Interchange</code>，美国信息交换标准代码）</h2>
<p>回到<code>Unix</code>正在被发明的上古时代，一个英文字符的<code>ASCII</code>值可以用 <code>32-127</code> 范围内的数字来表示，包括英文字母、数字和符号。
比如空格是<code>32</code>，<code>A</code>是<code>65</code>，<code>a</code>是<code>97</code>。 <code>0-31</code> 被用作操作符。如<code>10</code>为换行，<code>13</code>为回车。</p>
<p>计算机的最小寻址单位是一字节（<code>8</code>个比特），<code>127</code>只需要<code>7</code>个比特位就能表示（<code>2的7次方=128</code>），所以还有一比特位（值<code>128-255</code>）空闲。</p>
<p>这些空闲的值在不同的语言地区被赋予不同的用法。比如美洲地区用<code>130</code>来表示<code>é</code>，但是以色列的电脑用<code>130</code>来表示希伯来字符<code>ג</code>。那么在美洲电脑上显示的单词<code>résumés</code>，在以色列的电脑上就成了 <code>rגsumגs</code>。这导致了同一文档内容在不同的电脑上可能有不同的显示。</p>
<h2 id="code-page代码页">Code Page（代码页）</h2>
<p><code>ANSI</code>（<code>American National Standards Institute</code>，美国国家标准学会）在制定标准的时候，引入了代码页。</p>
<p>这些代码页<code>128</code>以下是一样的，只有<code>128</code>以上不同。如，以色列使用<code>code page 862</code>，希腊使用 <code>code page 737</code>。</p>
<p>这样在同一电脑上可以有多个不同的代码页可供选择。</p>
<h2 id="dbcsdouble-byte-character-set双字节字符集"><code>DBCS</code>（<code>Double Byte Character Set</code>，双字节字符集）</h2>
<p>但是，由于亚洲语言有成千上万的字符，没办法用一字节（<code>8</code>比特）完全表示。</p>
<p><code>DBCS</code> 是对英文字符使用单字节，其他字符（如中日韩文）使用双字节。访问文本时，只能从前向后处理。因为需要一直判断当前字节是不是前导字节，对于既有可能是前导也有可能是后续的字节，只能通过上下文做判断。</p>
<p>对计算机程序及程序员来说，操作起来比较麻烦、容易出错。</p>
<h2 id="unicode统一码万国码"><code>Unicode</code>（统一码、万国码）</h2>
<p>一套可以适用于全世界所有国家的字符集。</p>
<p>对 <code>Unicode</code> 最常见的误解是：每个字符占用<code>16</code>比特，因此能表示的字符个数是 <code>2的16次方=65536</code>个。实际上，这是不对的。</p>
<p><code>Unicode</code> 中对所有字母表中的每个字符分配一个数字——<code>code point</code>，如 <code>A</code> 的<code>code point</code> 是 <code>U+0041</code>；<code>迪</code>的 <code>code point</code> 是 <code>U+8FEA</code>。</p>
<p><code>Unicode</code> 中的字符，是一个概念定义。比如字符<code>A</code>，很明显<code>A</code>不同于<code>B</code>，也不同于<code>a</code>，但是无论是斜体的<code>A</code>、粗体的<code>A</code>、还是正常的<code>A</code>，它们应该是一样的，都是字符<code>A</code>。对于字体<code>Times New Roman</code>中的<code>A</code>，应该和字体<code>Helvetica</code>中的<code>A</code>一样，都是字符<code>A</code>。(对于字符<code>A</code>，<code>Unicode</code>只定义<code>U+0041</code>是字符<code>A</code>，而具体的这个字符显示出来时什么样子，是定义在字体文件中的)</p>
<h2 id="ucs-2--utf-16"><code>UCS-2</code> / <code>UTF-16</code></h2>
<p>那么 <code>He</code> 用 <code>Unicode</code> 表示就是 <code>00 48 00 65</code>。</p>
<p>对吗？憋着急。那它为啥不能是 <code>48 00 65 00</code> 呢？技术上来说没有问题，而实际上也是两种方式都存在（因为特定的 <code>CPU</code> 用特定的顺序会更快）——大端序（<code>big-edian</code>）和 小端序（<code>little-endian</code>）。</p>
<p>为了区分，在文本开头加上字节顺序标记位，大端序用 <code>FE FF</code>，小端序用 <code>FF FE</code>。</p>
<p>这种方式对于新生成的文档没有任何问题，但是无法兼容已有的<code>ASCII</code>和<code>DBCS</code>文档。</p>
<h2 id="utf-8unicode-transformation-format-8-bit">UTF-8（Unicode Transformation Format 8-bit）</h2>
<p>所以，出现了另一种实现 <code>Unicode</code> 字符集的系统——<code>UTF-8</code>。它采用变长的编码，用一个字节存储 <code>code point 0-127</code>，对 <code>128</code> 以上的使用 <code>2字节、3字节，最多到 6字节</code>。</p>
<p>比如，表示字符 <code>₤</code> 的 <code>Unicode</code> 十六进制值为 <code>U+20A4</code>，其二进制为 <code>0010 0000 1010 0100</code>。用<code>UTF-8</code> 来表示字符<code>₤</code>的话，需要<code>3</code>个字节：</p>
<ul>
<li>第一个字节的前四位，用<code>3</code>比特<code>1</code>（代表<code>3</code>个字节）加一个<code>0</code>：<code>1110</code>。后四位接<code>20A4</code>的前四子节：<code>0010</code>。得到<code>1110 0010</code>。</li>
<li>第二子节以<code>10</code>开头，后六字节接<code>20A4</code>的六字节 <code>0000 10</code>，得到<code>1000 0010</code>。</li>
<li>第三子节还是以<code>10</code>开头，后六字节接<code>20A4</code>最后六字节<code>10 0100</code>，得到<code>1010 0100</code>。</li>
</ul>
<p>最终得到字符<code>₤</code>的<code>UTF-8</code>表示为<code>1110-0010 1000-0010 1010-0100</code>。</p>
<blockquote>
<p>对于英文文档来说，<code>UTF-8</code> 和 <code>ASCII</code>是一样的，不需要任何转换。</p></blockquote>
<h3 id="utf-8-比-utf-16-省空间吗">UTF-8 比 UTF-16 省空间吗？</h3>
<p><strong>不一定</strong>。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">字符串</th>
          <th>UTF-8</th>
          <th>UTF-16</th>
          <th>空间比较</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center"><code>AI</code></td>
          <td><code>4149</code></td>
          <td><code>0041 0049</code></td>
          <td><code>UTF-8</code>&lt;<code>UTF-16</code></td>
      </tr>
      <tr>
          <td style="text-align: center"><code>射雕</code></td>
          <td><code>E5B0 84E9 9B95</code></td>
          <td><code>5C04 96D5</code></td>
          <td><code>UTF-8</code>&gt;<code>UTF-16</code></td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>如果存储数据英文字符较多，<code>UTF-8</code>肯定会比<code>UTF-16</code>节省空间。</p></blockquote>
<h2 id="encodings编码">Encodings（编码）</h2>
<p><img loading="lazy" src="/images/character-encoding.jpeg" alt="encoding"  /></p>
<p><code>Unicode</code>是字符集，上面说的 <code>UCS-2</code>、<code>UTF-8</code>等是实现<code>Unicode</code>的方法——<code>Encoding</code>。<code>Encoding</code>有多种实现，如<code>UTF-7</code>、<code>UTF-32</code>、<code>ISO8859-1</code>。</p>
<p>所以，必须确定所用的<code>Encoding</code>才能正确处理一个字符串。</p>
<p>在浏览器中看到这每个网页会有<code>Encoding</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&#34;Content-Type&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;text/html; charset=utf-8&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可是，在不知道<code>encoding</code>的情况下怎么去读这个<code>HTML</code>文件来取到<code>encoding</code>的信息呢？</p>
<p>幸运的是，绝大多数<code>encoding</code>对 <code>32-127</code> 的<code>code point</code>的处理方式是一样的，可以把文件开头的内容当作<code>ASCII</code>来处理。所以<code>encoding</code>信息越早出现越好，避免出现在任何<code>code point</code>大于<code>127</code>的字符之后。</p>
<p>另外，<code>HTTP</code>请求头中也可以包含<code>encoding</code>信息（<code>Content-Type</code>）。</p>
<p>早期的浏览器都有设置<code>encoding</code>的菜单，以应对找不到<code>encoding</code>定义而无法正确处理的情况。大部分现代浏览器（如<code>Chrome</code>）已经去掉该菜单，可以根据上下文判断出正确<code>encoding</code>了。</p>
<h2 id="原文链接">原文链接</h2>
<ul>
<li><a href="https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)</a></li>
<li><a href="https://mp.weixin.qq.com/s?__biz=Mzg5NDE1MTU2NQ==&amp;mid=2247483816&amp;idx=1&amp;sn=2be8183562976b65cbdc37c711ff79fb&amp;chksm=c022bf4af755365cf1440172cb044f204758796097fb42dfc028ff31c58505b5648e2478f10a&amp;token=258030414&amp;lang=zh_CN#rd">每个程序员都应该知道的字符集发展简史</a></li>
</ul>
<blockquote>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>设计模式：观察者模式、订阅-发布模式、事件监听模式</title>
      <link>https://blog.tomatostore.top/posts/2023/04/design-pattern-observer/</link>
      <pubDate>Tue, 11 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/design-pattern-observer/</guid>
      <description>Design Pattern: Observer Pattern</description>
      <content:encoded><![CDATA[<p>观察者模式（<code>Observer Pattern</code>）解决的对象间的一对多的关系，即一个被观察者与多个观察者。最直接的例子就是公众号（<code>Subject</code>）及订阅者（<code>Observer</code>）。</p>
<p>对于观察者模式、发布-订阅模式/事件监听模式，为只是相同技术实现基础上的不同演化，属于同一类设计模式。</p>
<hr>
<h2 id="观察者模式10">观察者模式1.0</h2>
<p>涉及两个角色：</p>
<ul>
<li>被观察者: Subject/Observable/Publisher, 会有状态/数据变化的对象。</li>
<li>观察者: Observer/Subscriber，关心<code>被观测对象</code>的变化。</li>
</ul>
<p>最基础的实现需要定义 2 个基类 <code>Subject</code> 和 <code>Observer</code>。</p>
<blockquote>
<p><code>C++</code>实现</p></blockquote>
<h3 id="观察者">观察者</h3>
<p>先定义接口类 <code>class Observer</code>，该类没有默认实现，子类必须实现 <code>update()</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Observer.h 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Observer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="n">string</span> <span class="n">msg</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// abstract virtual
</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><h3 id="被观察对象">被观察对象</h3>
<p>基类 <code>Subject</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Subject.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">addObserver</span><span class="p">(</span><span class="n">Observer</span> <span class="o">*</span> <span class="n">observer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">removeObserver</span><span class="p">(</span><span class="n">Observer</span> <span class="o">*</span> <span class="n">observer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">notify</span><span class="p">(</span><span class="n">string</span> <span class="n">msg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">private</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">set</span><span class="o">&lt;</span><span class="n">Observer</span><span class="o">*&gt;</span> <span class="n">observers</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><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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Subjet.cpp
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">addObserver</span><span class="p">(</span><span class="n">Observer</span><span class="o">*</span> <span class="n">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">observers</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">observer</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">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">removeObserver</span><span class="p">(</span><span class="n">Observer</span><span class="o">*</span> <span class="n">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">observers</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">observer</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">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">notify</span><span class="p">(</span><span class="n">string</span> <span class="n">msg</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">obs</span><span class="p">:</span> <span class="n">observers</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">obs</span><span class="o">-&gt;</span><span class="n">update</span><span class="p">(</span><span class="n">msg</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><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><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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl">
</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="k">class</span> <span class="nc">Publisher</span><span class="o">:</span> <span class="k">public</span> <span class="n">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">addArticle</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">article</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">articles</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">article</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">notify</span><span class="p">(</span><span class="n">article</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">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">articles</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="c1">// 订阅者
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">Subscriber</span><span class="o">:</span> <span class="k">public</span> <span class="n">Observer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Subscriber</span><span class="p">(</span><span class="n">string</span> <span class="n">name</span><span class="p">)</span><span class="o">:</span> <span class="n">name</span><span class="p">(</span><span class="n">name</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="k">virtual</span> <span class="kt">void</span> <span class="nf">update</span><span class="p">(</span><span class="n">string</span> <span class="n">article</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">readArticle</span><span class="p">(</span><span class="n">article</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">void</span> <span class="nf">readArticle</span><span class="p">(</span><span class="n">string</span> <span class="n">article</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">name</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; is reading article : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">article</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">name</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></span><span class="line"><span class="cl">    <span class="n">Publisher</span> <span class="n">publisher</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Subscriber</span> <span class="n">sub1</span><span class="p">(</span><span class="s">&#34;Tom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sub1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addArticle</span><span class="p">(</span><span class="s">&#34;Article 1&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</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="n">Subscriber</span> <span class="n">sub2</span><span class="p">(</span><span class="s">&#34;Jerry&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sub2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addArticle</span><span class="p">(</span><span class="s">&#34;Article 2&#34;</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">Tom</span> <span class="n">is</span> <span class="n">reading</span> <span class="nl">article</span> <span class="p">:</span> <span class="n">Article</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Tom</span> <span class="n">is</span> <span class="n">reading</span> <span class="nl">article</span> <span class="p">:</span> <span class="n">Article</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="n">Jerry</span> <span class="n">is</span> <span class="n">reading</span> <span class="nl">article</span> <span class="p">:</span> <span class="n">Article</span> <span class="mi">2</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="观察者模式20">观察者模式2.0</h2>
<p>上面的<code>Observer</code>提供了一个带有一个参数的<code>update</code>接口： <code>virtual void update(string msg)</code>。
虽然在应用中可以通过传递不同参数来区分不同的通知，比如：<code>update(&quot;全部订阅者可见更新&quot;)</code>，<code>update(&quot;VIP订阅者可见更新&quot;)</code>，但对于复杂一点的需要多参数传递的场景就不适用了。</p>
<p>那么可以通过引入<code>Event</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Event 接口定义
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">EventType</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ARTICLE_UPDATED</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">VIP_ARTICLE_UPDATED</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">class</span> <span class="nc">Event</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">virtual</span> <span class="n">EventType</span> <span class="n">type</span><span class="p">()</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">virtual</span> <span class="o">~</span><span class="n">Event</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="c1">// 具体的 Event 类型
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">ArticleUpdatedEvent</span><span class="o">:</span> <span class="k">public</span> <span class="n">Event</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">virtual</span> <span class="n">EventType</span> <span class="n">type</span><span class="p">()</span> <span class="k">override</span> <span class="p">{</span> <span class="k">return</span> <span class="n">ARTICLE_UPDATED</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="n">string</span> <span class="nf">getArticle</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">article</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">setArticle</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">article</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">article</span> <span class="o">=</span> <span class="n">article</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">article</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">class</span> <span class="nc">VipArticleUpdatedEvent</span><span class="o">:</span> <span class="k">public</span> <span class="n">Event</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">virtual</span> <span class="n">EventType</span> <span class="n">type</span><span class="p">()</span> <span class="k">override</span> <span class="p">{</span> <span class="k">return</span> <span class="n">VIP_ARTICLE_UPDATED</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="n">string</span> <span class="nf">getArticle</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">article</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">setArticle</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">article</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">article</span> <span class="o">=</span> <span class="n">article</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="kt">int</span> <span class="nf">getReward</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">reward</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">setReward</span><span class="p">(</span><span class="kt">int</span> <span class="n">reward</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">reward</span> <span class="o">=</span> <span class="n">reward</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">article</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">reward</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>Observer</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Observer.h 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Observer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// virtual void update(string msg) = 0; // abstract virtual
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="n">shared_pointer</span><span class="o">&lt;</span><span class="n">Event</span><span class="o">&gt;</span> <span class="n">event</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// abstract virtual
</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><code>Subject</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Subject.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// virtual void notify(string msg);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">notify</span><span class="p">(</span><span class="n">shared_pointer</span><span class="o">&lt;</span><span class="n">Event</span><span class="o">&gt;</span> <span class="n">event</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="p">};</span></span></span></code></pre></td></tr></table>
</div>
</div>
<p>应用到<code>公众号——订阅者</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><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="k">class</span> <span class="nc">Publisher</span><span class="o">:</span> <span class="k">public</span> <span class="n">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">addArticle</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">article</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">auto</span> <span class="n">e</span> <span class="o">=</span> <span class="n">make_shared</span><span class="o">&lt;</span><span class="n">ArticleUpdatedEvent</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">e</span><span class="o">-&gt;</span><span class="n">setArticle</span><span class="p">(</span><span class="n">article</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">notify</span><span class="p">(</span><span class="n">e</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">void</span> <span class="nf">addVipArticleWithReward</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">article</span><span class="p">,</span> <span class="kt">int</span> <span class="n">reward</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">auto</span> <span class="n">e</span> <span class="o">=</span> <span class="n">make_shared</span><span class="o">&lt;</span><span class="n">VipArticleUpdatedEvent</span><span class="o">&gt;</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">e</span><span class="o">-&gt;</span><span class="n">setArticle</span><span class="p">(</span><span class="n">article</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">e</span><span class="o">-&gt;</span><span class="n">setReward</span><span class="p">(</span><span class="n">reward</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">notify</span><span class="p">(</span><span class="n">e</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="p">};</span>
</span></span><span class="line"><span class="cl">
</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="k">class</span> <span class="nc">Subscriber</span><span class="o">:</span> <span class="k">public</span> <span class="n">Observer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Subscriber</span><span class="p">(</span><span class="n">string</span> <span class="n">name</span><span class="p">)</span><span class="o">:</span> <span class="n">name</span><span class="p">(</span><span class="n">name</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="k">virtual</span> <span class="kt">void</span> <span class="nf">update</span><span class="p">(</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Event</span><span class="o">&gt;</span> <span class="n">event</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">switch</span> <span class="p">(</span><span class="n">event</span><span class="o">-&gt;</span><span class="n">type</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="n">EventType</span><span class="o">::</span><span class="nl">ARTICLE_UPDATED</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">auto</span> <span class="n">e</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">ArticleUpdatedEvent</span><span class="o">*&gt;</span><span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">e</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">string</span> <span class="n">article</span> <span class="o">=</span> <span class="n">e</span><span class="o">-&gt;</span><span class="n">getArticle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">                    <span class="n">readArticle</span><span class="p">(</span><span class="n">article</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">break</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">case</span> <span class="n">EventType</span><span class="o">::</span><span class="nl">VIP_ARTICLE_UPDATED</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">auto</span> <span class="n">e</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">VipArticleUpdatedEvent</span><span class="o">*&gt;</span><span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">e</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">string</span> <span class="n">vipArticle</span> <span class="o">=</span> <span class="n">e</span><span class="o">-&gt;</span><span class="n">getArticle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">                    <span class="n">readArticle</span><span class="p">(</span><span class="n">vipArticle</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">int</span> <span class="n">reward</span> <span class="o">=</span> <span class="n">e</span><span class="o">-&gt;</span><span class="n">getReward</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">                    <span class="n">earnReward</span><span class="p">(</span><span class="n">reward</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">break</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">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">break</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="nf">readArticle</span><span class="p">(</span><span class="n">string</span> <span class="n">article</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">name</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; is reading article : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">article</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">void</span> <span class="nf">earnReward</span><span class="p">(</span><span class="kt">int</span> <span class="n">reward</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">name</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; earned reward : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">reward</span> <span class="o">&lt;&lt;</span> <span class="n">endl</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">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">name</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></span><span class="line"><span class="cl">    <span class="n">Publisher</span> <span class="n">publisher</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Subscriber</span> <span class="n">sub1</span><span class="p">(</span><span class="s">&#34;Tom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sub1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addArticle</span><span class="p">(</span><span class="s">&#34;Article 1&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</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="n">Subscriber</span> <span class="n">sub2</span><span class="p">(</span><span class="s">&#34;Jerry&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sub2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addVipArticleWithReward</span><span class="p">(</span><span class="s">&#34;Article 2&#34;</span><span class="p">,</span> <span class="mi">5</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>
<pre tabindex="0"><code>Tom is reading article : Article 1

Tom is reading article : Article 2
Tom earned reward : 5
Jerry is reading article : Article 2
Jerry earned reward : 5
</code></pre><p>通过继承<code>Event</code>，这个版本支持灵活的扩展通知类型，对传递的参数个数和类型没有任何限制。</p>
<p>目前为止，被订阅对象发送 <code>notify</code> 时对所有的订阅者都是一视同仁的，也就是说每个订阅者接收到的消息是一样的。</p>
<p>对于上面公众号的例子，如果想实现对 VIP 订阅者和普通订阅者推送不同的通知，那就可以通过如下的方式。</p>
<hr>
<h2 id="观察者模式30">观察者模式3.0</h2>
<p>更改 <code>Subject</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Subject.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Subject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="n">addObserver</span><span class="p">(</span><span class="n">EventType</span> <span class="n">type</span><span class="p">,</span> <span class="n">Observer</span> <span class="o">*</span> <span class="n">observer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">removeObserver</span><span class="p">(</span><span class="n">EventType</span> <span class="n">type</span><span class="p">,</span> <span class="n">Observer</span> <span class="o">*</span> <span class="n">observer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">notify</span><span class="p">(</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Event</span><span class="o">&gt;</span> <span class="n">event</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">private</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">map</span><span class="o">&lt;</span><span class="n">EventType</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">set</span><span class="o">&lt;</span><span class="n">Observer</span><span class="o">*&gt;</span> <span class="o">&gt;</span> <span class="n">observers</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="c1">// Subjet.cpp
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">addObserver</span><span class="p">(</span><span class="n">EventType</span> <span class="n">type</span><span class="p">,</span> <span class="n">Observer</span><span class="o">*</span> <span class="n">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">observers</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">insert</span><span class="p">(</span><span class="n">observer</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">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">removeObserver</span><span class="p">(</span><span class="n">EventType</span> <span class="n">type</span><span class="p">,</span> <span class="n">Observer</span><span class="o">*</span> <span class="n">observer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">observers</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">erase</span><span class="p">(</span><span class="n">observer</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">void</span> <span class="n">Subject</span><span class="o">::</span><span class="n">notify</span><span class="p">(</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Event</span><span class="o">&gt;</span> <span class="n">event</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">obs</span><span class="p">:</span> <span class="n">observers</span><span class="p">[</span><span class="n">event</span><span class="o">-&gt;</span><span class="n">type</span><span class="p">()])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">obs</span><span class="o">-&gt;</span><span class="n">update</span><span class="p">(</span><span class="n">event</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>修改<code>main</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><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">Publisher</span> <span class="n">publisher</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Subscriber</span> <span class="n">sub1</span><span class="p">(</span><span class="s">&#34;Tom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="n">EventType</span><span class="o">::</span><span class="n">ARTICLE_UPDATED</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sub1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addArticle</span><span class="p">(</span><span class="s">&#34;Article 1&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</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="n">Subscriber</span> <span class="n">sub2</span><span class="p">(</span><span class="s">&#34;Jerry&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addObserver</span><span class="p">(</span><span class="n">EventType</span><span class="o">::</span><span class="n">VIP_ARTICLE_UPDATED</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sub2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">publisher</span><span class="p">.</span><span class="n">addVipArticleWithReward</span><span class="p">(</span><span class="s">&#34;VIP Article 2&#34;</span><span class="p">,</span> <span class="mi">5</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>
<pre tabindex="0"><code>Tom is reading article : Article 1

Jerry is reading article : VIP Article 2
Jerry earned reward : 5
</code></pre><p>此版本进化到了一个更为特殊的观察者模式———发布订阅者模式，或者叫事件订阅模式。</p>
<h3 id="observer-pattern-vs-publish-subscribe-pattern">Observer Pattern v.s. Publish-Subscribe Pattern</h3>
<p>其主要区别是观察者模式涉及两种角色 <code>Subject</code> 和 <code>Observer</code>，而发布订阅模式中间多了一个<code>Event</code>处理，有的称之为<code>Broker</code>或<code>Channel</code>:</p>
<p><img loading="lazy" src="/images/observer-pattern-v.s.-publish-subscript-pattern.jpeg" alt="Observer Pattern v.s. Publish-Subscribe Pattern"  /></p>
<hr>
<h2 id="完整代码">完整代码</h2>
<ul>
<li><a href="https://github.com/AidySun/aidysun.github.io/tree/main/src/design-pattern-observer.v1.0.cpp">design-pattern-observer v1.0.cpp</a></li>
<li><a href="https://github.com/AidySun/aidysun.github.io/tree/main/src/design-pattern-observer.v2.0.cpp">design-pattern-observer v2.0.cpp</a></li>
<li><a href="https://github.com/AidySun/aidysun.github.io/tree/main/src/design-pattern-observer.v3.0.cpp">design-pattern-observer v3.0.cpp</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swift: beginAnimations(_:context:) was deprecated in iOS 13.0: Use the block-based animation API instead</title>
      <link>https://blog.tomatostore.top/posts/2023/04/swift-block-based-animation/</link>
      <pubDate>Sun, 02 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/04/swift-block-based-animation/</guid>
      <description>Swift / Objective-C block-based animation</description>
      <content:encoded><![CDATA[<p>用 <code>Xcode 14.2</code> 升级一个 <code>Swift</code> 项目时有编译警告️⚠提示 <code>beginAnimations()</code> 在 <code>iOS 13.0</code> 后已经不推荐使用，应该用 <code>block-based animation</code> 代替。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="hl"><span class="lnt">1
</span></span><span class="hl"><span class="lnt">2
</span></span><span class="hl"><span class="lnt">3
</span></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-swift" data-lang="swift"><span class="line hl"><span class="cl"><span class="n">UIView</span><span class="p">.</span><span class="n">beginAnimations</span><span class="p">(</span><span class="kc">nil</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span> <span class="c1">// &#39;beginAnimations(_:context:)&#39; was deprecated in iOS 13.0: Use the block-based animation API instead</span>
</span></span><span class="line hl"><span class="cl"><span class="n">UIView</span><span class="p">.</span><span class="n">setAnimationDuration</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="c1">// &#39;setAnimationDuration&#39; was deprecated in iOS 13.0: Use the block-based animation API instead</span>
</span></span><span class="line hl"><span class="cl"><span class="n">UIView</span><span class="p">.</span><span class="n">commitAnimations</span><span class="p">()</span> <span class="c1">// &#39;commitAnimations()&#39; was deprecated in iOS 13.0: Use the block-based animation API instead </span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">currentOverlay</span> <span class="p">=</span> <span class="n">overlay</span>
</span></span><span class="line"><span class="cl"><span class="n">currentOverlayTarget</span> <span class="p">=</span> <span class="n">overlayTarget</span>
</span></span><span class="line"><span class="cl"><span class="n">currentLoadingText</span> <span class="p">=</span> <span class="n">loadingText</span></span></span></code></pre></td></tr></table>
</div>
</div>
<p>修改为使用 <code>Block-based animation</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="n">UIView</span><span class="p">.</span><span class="n">animate</span><span class="p">(</span><span class="n">withDuration</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentOverlay</span> <span class="p">=</span> <span class="n">overlay</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentOverlayTarget</span> <span class="p">=</span> <span class="n">overlayTarget</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentLoadingText</span> <span class="p">=</span> <span class="n">loadingText</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>如果用 <code>Objective-C</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">[</span><span class="n">UIView</span> <span class="nl">animateWithDuration</span><span class="p">:</span> <span class="mf">0.5</span>
</span></span><span class="line"><span class="cl">                 <span class="nl">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentOverlay</span> <span class="o">=</span> <span class="n">overlay</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentOverlayTarget</span> <span class="o">=</span> <span class="n">overlayTarget</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">currentLoadingText</span> <span class="o">=</span> <span class="n">loadingText</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>]]></content:encoded>
    </item>
    
    <item>
      <title>能否在 C&#43;&#43; 的构造函数中使用 this 指针</title>
      <link>https://blog.tomatostore.top/posts/2023/03/this-pointer-in-cpp-ctor/</link>
      <pubDate>Mon, 27 Mar 2023 22:07:21 +0800</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/03/this-pointer-in-cpp-ctor/</guid>
      <description>构造函数没执行完，this不可以用？继承多态中父类能否用this指针触发多态调用？</description>
      <content:encoded><![CDATA[<p>直接说结论：<strong>可以在构造函数中使用 this，但是，多态无法生效。</strong></p>
<p>有人认为在构造函数中，对象的构造还没有完成，不能使用 this 指针。
根据<a href="https://isocpp.org/wiki/faq/ctors#using-this-in-ctors">Should you use the this pointer in the constructor?</a>的描述，在构造函数的函数体中使用this指针可以放心的访问父类和自己类中定义的数据成员（data members）。因为那些数据成员在构造函数开始执行时已经构造完成了。</p>
<blockquote>
<p>Here is something that always works: the {body} of a constructor (or a function called from the constructor) can reliably access the data members declared in a base class and/or the data members declared in the constructor’s own class. This is because all those data members are guaranteed to have been fully constructed by the time the constructor’s {body} starts executing.</p></blockquote>
<p>但要<strong>注意</strong>在有继承的情况下，即使是正在构造一个子类实例，在父类的构造阶段，当前的实例还不是子类型。</p>
<blockquote>
<p>The bottom line is this: even if the caller is constructing an object of a derived class, during the constructor of the base class, your object is not yet of that derived class. You have been warned.</p></blockquote>
<p>这也就导致了在父类的构造函数中，this指针是无法触发多态，也就是无法调用到正确的虚函数（virtual functions）。</p>
<blockquote>
<p>Here is something that never works: the {body} of a constructor (or a function called from the constructor) cannot get down to a derived class by calling a virtual member function that is overridden in the derived class. If your goal was to get to the overridden function in the derived class, you won’t get what you want. Note that you won’t get to the override in the derived class independent of how you call the virtual member function: explicitly using the this pointer (e.g., this-&gt;method()), implicitly using the this pointer (e.g., method()), or even calling some other function that calls the virtual member function on your this object.</p></blockquote>
<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="hl"><span class="lnt">10
</span></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="hl"><span class="lnt">25
</span></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="hl"><span class="lnt">57
</span></span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">A</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;A() { </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">    <span class="k">this</span><span class="o">-&gt;</span><span class="n">vf</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="o">-&gt;</span><span class="n">f1</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;} </span><span class="se">\n</span><span class="s">&#34;</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="o">~</span><span class="n">A</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;~A()</span><span class="se">\n</span><span class="s">&#34;</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">virtual</span> <span class="kt">void</span> <span class="nf">vf</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;  A&#39;s vf()</span><span class="se">\n</span><span class="s">&#34;</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">void</span> <span class="nf">f1</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;  A&#39;s f1()</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">    <span class="n">vf</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="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">B</span> <span class="o">:</span> <span class="k">public</span> <span class="n">A</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">B</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;B() { </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="o">-&gt;</span><span class="n">vf</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="o">-&gt;</span><span class="n">f1</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;} </span><span class="se">\n</span><span class="s">&#34;</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="o">~</span><span class="n">B</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;~B()</span><span class="se">\n</span><span class="s">&#34;</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">virtual</span> <span class="kt">void</span> <span class="nf">vf</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;  B&#39;s vf()</span><span class="se">\n</span><span class="s">&#34;</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">void</span> <span class="nf">f1</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;  B&#39;s f1()</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">vf</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="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">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;creat A a</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">A</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;creat B b</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">  <span class="n">B</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="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;======</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</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="hl"><span class="lnt"> 9
</span></span><span class="lnt">10
</span><span class="hl"><span class="lnt">11
</span></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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">creat A a
</span></span><span class="line"><span class="cl">A<span class="o">()</span> <span class="o">{</span> 
</span></span><span class="line"><span class="cl">  A<span class="s1">&#39;s vf()
</span></span></span><span class="line"><span class="cl"><span class="s1">  A&#39;</span>s f1<span class="o">()</span>
</span></span><span class="line"><span class="cl">  A<span class="s1">&#39;s vf()
</span></span></span><span class="line"><span class="cl"><span class="s1">} 
</span></span></span><span class="line"><span class="cl"><span class="s1">creat B b  // 开始构造 B b;
</span></span></span><span class="line"><span class="cl"><span class="s1">A() { 
</span></span></span><span class="line hl"><span class="cl"><span class="s1">  A&#39;</span>s vf<span class="o">()</span> // 在B的构造过程中，父类A中的this调用的是A的virtual <span class="k">function</span> 
</span></span><span class="line"><span class="cl">  A<span class="s1">&#39;s f1()
</span></span></span><span class="line hl"><span class="cl"><span class="s1">  A&#39;</span>s vf<span class="o">()</span> // 同样，在父类构造函数中间接调用的虚函数，也不会调用子类的虚函数
</span></span><span class="line"><span class="cl"><span class="o">}</span> 
</span></span><span class="line"><span class="cl">B<span class="o">()</span> <span class="o">{</span> 
</span></span><span class="line"><span class="cl">  B<span class="s1">&#39;s vf()
</span></span></span><span class="line"><span class="cl"><span class="s1">  B&#39;</span>s f1<span class="o">()</span>
</span></span><span class="line"><span class="cl">  B<span class="err">&#39;</span>s vf<span class="o">()</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span> 
</span></span><span class="line"><span class="cl"><span class="o">======</span>
</span></span><span class="line"><span class="cl">~B<span class="o">()</span>
</span></span><span class="line"><span class="cl">~A<span class="o">()</span>
</span></span><span class="line"><span class="cl">~A<span class="o">()</span></span></span></code></pre></td></tr></table>
</div>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>如何删除本地 git 中未追踪的文件/文件夹</title>
      <link>https://blog.tomatostore.top/posts/2023/03/git-rm-untracked-file-dir/</link>
      <pubDate>Fri, 24 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.tomatostore.top/posts/2023/03/git-rm-untracked-file-dir/</guid>
      <description>git clean/delete untracked files, folders</description>
      <content:encoded><![CDATA[<p>对于一个 git 项目，执行 <code>git status -u</code> 有如下状态：</p>
<p><img loading="lazy" src="/images/git-status--u.png" alt="git status -u result"  title="hi"  /></p>
<p>对于本地新增的文件，可以通过 <code>clean</code> 命令直接删除：</p>
<p><img loading="lazy" src="/images/git-clean--f.png" alt="git clean -f"  /></p>
<p><img loading="lazy" src="/images/git-status--u-2.png" alt="after clean"  /></p>
<p>但是本地新增的文件夹却没有被删除掉。要删除文件夹需要加上 <code>-d</code> 参数：</p>
<p><img loading="lazy" src="/images/git-clean-fd.png" alt="git clean -f -d"  /></p>
<p>还有一种情况就是已经在 <code>.gitignore</code> 中的文件或文件夹是不会被删除的。</p>
<p><img loading="lazy" src="/images/cat-.gitignore.png" alt="cat .gitignore"  /></p>
<p><img loading="lazy" src="/images/git-status---ignored.png" alt="git status &ndash;ignored"  /></p>
<p>需要通过 <code>-x</code> 选项来删除被 <code>.gitignore</code> 包含的文件或文件夹：</p>
<p><img loading="lazy" src="/images/git-clean--fdx.png" alt="git clean -f -d -x"  /></p>
<h2 id="git-clean-options"><code>git clean</code> options</h2>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Option</th>
          <th>Comments</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center"><code>-f</code></td>
          <td><em>Delete files or diretories</em></td>
      </tr>
      <tr>
          <td style="text-align: center"><code>-d</code></td>
          <td><em>Recurse into untracked directories</em></td>
      </tr>
      <tr>
          <td style="text-align: center"><code>-x</code></td>
          <td><em>Don’t use the standard ignore rules</em></td>
      </tr>
  </tbody>
</table>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
