-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
301 lines (163 loc) · 245 KB
/
atom.xml
File metadata and controls
301 lines (163 loc) · 245 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>故乡</title>
<subtitle>星辰大海</subtitle>
<link href="http://hkeepl.github.io/atom.xml" rel="self"/>
<link href="http://hkeepl.github.io/"/>
<updated>2022-08-27T08:46:26.351Z</updated>
<id>http://hkeepl.github.io/</id>
<author>
<name>HeYin</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>办公电脑加密文件解密</title>
<link href="http://hkeepl.github.io/posts/31044"/>
<id>http://hkeepl.github.io/posts/31044</id>
<published>2022-08-16T13:04:32.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="抱歉, 这个密码看着不太对, 请再试试。" data-whm="抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容。"> <script id="hbeData" type="hbeData" data-hmacdigest="bd56be8c41e5a577456ba88e44dcf5caf7c2ec80732a5c8ffe96a03ecc5fd64f">645de0d46aae26e548096beabbdb3944f2c9fb36c0ea16aba6686face1423aea</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-default"> <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass"> <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-default">请输入密码,查看文章。</span> </label> </div> </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
<summary type="html">这是一篇加密文章,内容可能是个人情感宣泄或者收费技术。如果你确实想看,请与我联系。</summary>
<category term="加密文章" scheme="http://hkeepl.github.io/tags/%E5%8A%A0%E5%AF%86%E6%96%87%E7%AB%A0/"/>
</entry>
<entry>
<title>使用QFileDialog选择多文件夹</title>
<link href="http://hkeepl.github.io/posts/61783"/>
<id>http://hkeepl.github.io/posts/61783</id>
<published>2022-08-14T05:13:48.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>用户希望在界面上可以选择多个文件夹作为应用程序的数据输入,但是<code>QFileDialog</code>不支持该功能,使用<code>QFileDialog</code>只能够选择单个文件夹,或者一个文件夹下的多个文件。为了实现这个功能,搜索了一些网页,最终得以实现,下面对这个实现过程做个记录。</p><span id="more"></span><p>在原生的FileDialog中是不支持选择多个文件夹的,但在Qt的帮助文档中可以看到,我们可以将对话框类型设置为:<code>QFileDialog::DontUseNativeDialog</code>,使用非原生的文件选择对话框,实现多文件夹选择。</p><table><thead><tr><th>枚举常量</th><th>说明</th></tr></thead><tbody><tr><td>QFileDialog::DontUseNativeDialog</td><td>不使用原生的文件对话框。默认地,只在继QFileDialog的继承类中包含元信息(<code>Q_OBJECT</code>),或者原生文件对话框不支持我们想要的功能时使用非原生文件选择对话框。</td></tr></tbody></table><p>参考网络上搜索的结果,具体的实现如下:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> file_dialog = <span class="keyword">new</span> <span class="built_in">QFileDialog</span>(<span class="keyword">this</span>);</span><br><span class="line"><span class="comment">// 设置对话框选择文件夹</span></span><br><span class="line">file_dialog-><span class="built_in">setFileMode</span>(QFileDialog::DirectoryOnly);</span><br><span class="line"><span class="comment">// 设置对话框为非原生对话框</span></span><br><span class="line">file_dialog-><span class="built_in">setOption</span>(QFileDialog::DontUseNativeDialog);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在非原生的 QFileDialog 中,对话框中当前文件夹下的文件或文件夹可以按照列表或者树的形式进行显</span></span><br><span class="line"><span class="comment"> * 示,因此,应该处理两种显示模式,具体地,如下面的代码实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// list</span></span><br><span class="line"><span class="keyword">auto</span> list_view = file_dialog-><span class="built_in">findChild</span><QListView *>(<span class="string">"listView"</span>);</span><br><span class="line"><span class="keyword">if</span>(list_view) {</span><br><span class="line"> list_view-><span class="built_in">setSelectionMode</span>(QAbstractItemView::MultiSelection);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// tree</span></span><br><span class="line"><span class="keyword">auto</span> tree_view = file_dialog-><span class="built_in">findChild</span><QTreeView *>();</span><br><span class="line"><span class="keyword">if</span>(tree_view) {</span><br><span class="line"> tree_view-><span class="built_in">setSelectionMode</span>(QAbstractItemView::MultiSelection);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">auto</span> ret_code = file_dialog-><span class="built_in">exec</span>();</span><br><span class="line"><span class="keyword">if</span>(!ret_code) {</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"Canceled"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">auto</span> selected_files = file_dialog-><span class="built_in">selectedFiles</span>();</span><br></pre></td></tr></table></figure><p>几乎网络上给出的所有实现都是类似上面这样的,但是自己实际使用时发现,如果我想在一个父文件夹下选择多个子文件夹,因为我是需要双击父文件夹才能进入当前文件夹的,这就会导致我最终不但会在子文件夹下选择了多个文件夹,而且还会选中父文件夹。说的简单点,父文件夹或当前子文件夹下的所有文件夹都会在第一次被双击或单击时选中。而这,是我不希望的。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">root_folder</span><br><span class="line"> |--sub_folder1</span><br><span class="line"> |--sub_folder2</span><br><span class="line"> |--sub_folder3</span><br><span class="line"> |--sub_folder4</span><br></pre></td></tr></table></figure><p>即,如果在上面的文件夹下,我想要选择 sub_folder2 和 sub_folder4,因为我要双击 root_folder 才能进入当前文件夹,我在选择了 sub_folder2 和 sub_folder4,最终我得到的选择文件夹是: root_folder,sub_folder2 和 sub_folder4。</p><p>查阅 <code>QAbstractItemView</code> 的帮助文档,发现可以通过切换 SelectionMode 实现想要的功能,设置值的功能对比如下表:</p><table><thead><tr><th>枚举常量</th><th>说明</th></tr></thead><tbody><tr><td>QAbstractItemView::MultiSelection</td><td>当用户以常规的方式选择一个项目时,该项目的选择状态将会被切换,而其他项目则保持不变,可以通过鼠标拖动到多个项目上切换它们的状态。</td></tr><tr><td>QAbstractItemView::ExtendedSelection</td><td>当用户以常规的方式选择一个项目时,选择状态被清楚并且选择新项目。但是,如果用户在按下Ctrl键的同时点击一个项目,则单击的项目的状态被切换,而所有其他项目保持不变。如果用户在点击一个项目的同时按下Shift键,则当前项目和单击项目之间的所有项目都被选中或取消选中,具体取决于单击项目的状态。可以通过鼠标拖动到多个项目上选择它们。</td></tr></tbody></table><p>因此,这里我们可以将上面代码中的<code>QAbstractItemView::MultiSelection</code>改为 <code>QAbstractItemView::ExtendedSelection</code>即可。最终代码实现如下:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> file_dialog = <span class="keyword">new</span> <span class="built_in">QFileDialog</span>(<span class="keyword">this</span>);</span><br><span class="line"><span class="comment">// 设置对话框选择文件夹</span></span><br><span class="line">file_dialog-><span class="built_in">setFileMode</span>(QFileDialog::DirectoryOnly);</span><br><span class="line"><span class="comment">// 设置对话框为非原生对话框</span></span><br><span class="line">file_dialog-><span class="built_in">setOption</span>(QFileDialog::DontUseNativeDialog);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在非原生的 QFileDialog 中,对话框中当前文件夹下的文件或文件夹可以按照列表或者树的形式进行显</span></span><br><span class="line"><span class="comment"> * 示,因此,应该处理两种显示模式,具体地,如下面的代码实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// list</span></span><br><span class="line"><span class="keyword">auto</span> list_view = file_dialog-><span class="built_in">findChild</span><QListView *>(<span class="string">"listView"</span>);</span><br><span class="line"><span class="keyword">if</span>(list_view) {</span><br><span class="line"> list_view-><span class="built_in">setSelectionMode</span>(QAbstractItemView::ExtendedSelection);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// tree</span></span><br><span class="line"><span class="keyword">auto</span> tree_view = file_dialog-><span class="built_in">findChild</span><QTreeView *>();</span><br><span class="line"><span class="keyword">if</span>(tree_view) {</span><br><span class="line"> tree_view-><span class="built_in">setSelectionMode</span>(QAbstractItemView::ExtendedSelection);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">auto</span> ret_code = file_dialog-><span class="built_in">exec</span>();</span><br><span class="line"><span class="keyword">if</span>(!ret_code) {</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"Canceled"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">auto</span> selected_files = file_dialog-><span class="built_in">selectedFiles</span>();</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>用户希望在界面上可以选择多个文件夹作为应用程序的数据输入,但是<code>QFileDialog</code>不支持该功能,使用<code>QFileDialog</code>只能够选择单个文件夹,或者一个文件夹下的多个文件。为了实现这个功能,搜索了一些网页,最终得以实现,下面对这个实现过程做个记录。</p></summary>
<category term="Qt" scheme="http://hkeepl.github.io/tags/Qt/"/>
</entry>
<entry>
<title>解决从GitHub上传代码总是失败的问题</title>
<link href="http://hkeepl.github.io/posts/55693"/>
<id>http://hkeepl.github.io/posts/55693</id>
<published>2022-07-23T01:02:20.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>在国内,GitHub本来可能上不了,即使上得了速度也很慢。这里的解决的问题是:开了VPN后,也经常上传失败。这里对解决的流程做一记录,方便查阅。</p><span id="more"></span><h2 id="设置代理"><a href="#设置代理" class="headerlink" title="设置代理"></a>设置代理</h2><p>这里我使用的是http代理,设置方法如下:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global http.proxy http://<span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span>:your_proxy_port</span><br><span class="line">git config --global https.proxy https://<span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span>:your_proxy_port</span><br></pre></td></tr></table></figure><p>代理端口,可以通过<code>设置->网络和Internet->代理</code>查看。</p><p>示例:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global http.proxy http://<span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span>:<span class="number">10809</span></span><br><span class="line">git config --global https.proxy https://<span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span>:<span class="number">10809</span></span><br></pre></td></tr></table></figure><h2 id="查看设置了哪些代理"><a href="#查看设置了哪些代理" class="headerlink" title="查看设置了哪些代理"></a>查看设置了哪些代理</h2><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global http.proxy</span><br><span class="line">git config --global https.proxy</span><br></pre></td></tr></table></figure><h2 id="取消代理"><a href="#取消代理" class="headerlink" title="取消代理"></a>取消代理</h2><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global --unset http.proxy</span><br><span class="line">git config --global --unset https.proxy </span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>在国内,GitHub本来可能上不了,即使上得了速度也很慢。这里的解决的问题是:开了VPN后,也经常上传失败。这里对解决的流程做一记录,方便查阅。</p></summary>
<category term="GitHub" scheme="http://hkeepl.github.io/tags/GitHub/"/>
</entry>
<entry>
<title>在CPack中使用windeployqt</title>
<link href="http://hkeepl.github.io/posts/11227"/>
<id>http://hkeepl.github.io/posts/11227</id>
<published>2022-07-23T00:56:48.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>Qt是一个非常优秀的跨平台C++应用程序开发工具包,CMake/CPack 是一款非常出色的C++应用程序构建系统(基本上目前也已经成为C++构建系统的标准了)。它们两个可以很好的结合在一起,而且我在很多项目中也已经使用了它们。然而,使用CPack部署包含Qt的项目,却并非易事。这篇文章将描述我是怎么尝试解决这个问题的。</p><span id="more"></span><h2 id="一个简单的例子"><a href="#一个简单的例子" class="headerlink" title="一个简单的例子"></a>一个简单的例子</h2><p>在准备应用程序安装包时,CPack构建默认目标,并且捆绑install命令指示的文件。比如下面的可执行程序:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">add_executable</span>(myapp WIN32 main.cpp)</span><br><span class="line"><span class="keyword">install</span>(TARGETS myapp DESTINATION bin)</span><br></pre></td></tr></table></figure><p>在基于Unix的平台下,上述命令会执行:生成myapp的可执行文件,然后将它拷贝到<code>/usr/local/bin</code>目录下。在Windows中,类似地,生成myapp可执行文件,然后会将它拷贝到<code>${CMAKE_INSTALL_PREFIX}/bin</code>目录中。</p><p>如果我们添加CPack命令,并且在命令行中调用下面的命令,便可以生成一个应用程序安装包了(前提:安装了NSIS):</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">add_executable</span>(myapp WIN32 main.cpp)</span><br><span class="line"><span class="keyword">install</span>(TARGETS myapp DESTINATION bin)</span><br><span class="line"><span class="keyword">include</span>(CPack)</span><br></pre></td></tr></table></figure><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cpack -G NSIS</span><br></pre></td></tr></table></figure><h2 id="说明问题在哪里"><a href="#说明问题在哪里" class="headerlink" title="说明问题在哪里"></a>说明问题在哪里</h2><p>这里有一个小问题,上面生成的应用程序安装包中只是包含了编译生成的可执行文件,并没有用用程序运行时需要的任何库文件。比如,如果使用Visual C++编译的应用程序,MSVC的运行库就没有包含在安装包中;如果应用程序开发时使用了Qt,Qt的运行时库,平台插件等也没有包含在安装包中。</p><p>CMake对MSVC的运行时库以<code>InstallRequiredSystemLibraries</code>的方式提供了解决方案:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 如果应用程序使用Visual Studio 2015或者更新的版本</span></span><br><span class="line"><span class="keyword">set</span>(CMAKE_INSTALL_UCRT_LIBRARIES <span class="keyword">TRUE</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span>(InstallRequiredSystemLibraries)</span><br></pre></td></tr></table></figure><p>但是这并没有解决Qt的问题。</p><h2 id="windeployqt"><a href="#windeployqt" class="headerlink" title="windeployqt"></a>windeployqt</h2><p><a href="https://doc.qt.io/qt-5/windows-deployment.html">windeployqt</a>是Qt提供的一个简化应用程序安装的工具,只需要将应用程序的完整路径传递给windeployqt,windeployqt就会将所有的依赖库,插件等相关的依赖文件拷贝到应用程序所在的目录中:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">windeployqt <span class="built_in">path</span>/to/myapp.exe</span><br></pre></td></tr></table></figure><p>将这个过程集成到CMake中尽管有些复杂,但也是可行的。首先需要获得windeployqt的绝对路径,它和qmake在相同的目录下,所以我们可以通过下面的命令获取windeployqt的绝对路径:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># find_package(Qt5Core REQUIRED)</span></span><br><span class="line"><span class="keyword">get_target_property</span>(QMAKE_EXECUTABLE_ABS_PATH Qt5::make IMPORTED_LOCATION)</span><br><span class="line"><span class="keyword">get_filename_component</span>(QT_BIN_DIR <span class="string">"${QMAKE_EXECUTABLE_ABS_PATH}"</span> DIRECTORY)</span><br><span class="line"><span class="keyword">find_program</span>(WINDEPLOYQT_EXECUTABLE windeployqt HINTS <span class="string">"${QT_BIN_DIR}"</span>)</span><br></pre></td></tr></table></figure><p>然后通过一个自定义命令就可以在CMake中调用windeployqt了:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">add_custom_command</span>(<span class="keyword">TARGET</span> myapp POST_BUILD</span><br><span class="line"> <span class="keyword">COMMAND</span> <span class="string">"${CMAKE_COMMAND}"</span> -E </span><br><span class="line"> env PATH=<span class="string">"${QT_BIN_DIR}"</span> <span class="string">"${WINDEPLOYQT_EXECUTABLE}"</span></span><br><span class="line"> --verbose <span class="number">0</span></span><br><span class="line"> --no-compiler-runtime</span><br><span class="line"> \<span class="string">"$<TARGET_FILE:myapp>\"</span></span><br><span class="line"><span class="string"> COMMENT "</span>Deploying Qt...<span class="string">")</span></span><br></pre></td></tr></table></figure><p>注意:</p><ol><li><code>env</code>:是为了使windeployqt能够找到Qt的依赖文件;</li><li><code>--no-compiler-runtime</code>:因为Qt在部署编译器运行时存在问题,所以这里使用这个选项禁用了使用windeployqt安装编译器运行时,使用CMake的InstallRequiredSystemLibraries 代替。</li></ol><h2 id="仍然存在的问题"><a href="#仍然存在的问题" class="headerlink" title="仍然存在的问题"></a>仍然存在的问题</h2><p>然而,经过上面的优化,仍然不能解决最开始的问题,应用程序依赖的Qt文件仍然不能包含在CPack调用中。因为,只有显示使用了install命令安装的文件才能被包含在CPack的调用中。这看似是一个不可逾越的问题:如何在构建应用程序之前,即应用程序不存在的时候,通过install()创建对这个应用程序依赖的安装。</p><p>解决这个问题的第一步,我们在调用windeployqt时,传递一些具体的参数:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">windeployqt --dry-run --list mapping <span class="built_in">path</span>/to/myapp.exe</span><br></pre></td></tr></table></figure><p>这会改变windeployqt工具的行为,它只是打印出来了应用程序依赖的具体文件和相对路径,并不会拷贝这些文件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">"C:\Qt\5.15.2\msvc2019_64\bin\Qt5Cored.dll" "Qt5Cored.dll"</span><br><span class="line">"C:\Qt\5.15.2\msvc2019_64\bin\Qt5Guid.dll" "Qt5Guid.dll"</span><br><span class="line">"C:\Qt\5.15.2\msvc2019_64\bin\Qt5Svgd.dll" "Qt5Svgd.dll"</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>看起来很有希望,有一个CMake命令可以捕获命令的输出——<code>execute_process()</code>,其实现可能类似于以下内容:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">execute_process</span>(<span class="keyword">COMMAND</span> <span class="string">"${CMAKE_COMMAND}"</span> -E</span><br><span class="line"> env PATH=<span class="string">"${QT_BIN_DIR}"</span> <span class="string">"${WINDEPLOYQT_EXECUTABLE}"</span></span><br><span class="line"> --dry-run</span><br><span class="line"> --<span class="keyword">list</span> mapping</span><br><span class="line"> --no-compiler-runtime</span><br><span class="line"> \<span class="string">"$<TARGET_FILE:myapp>\"</span></span><br><span class="line"><span class="string"> OUTPUT_VARIABLE _output</span></span><br><span class="line"><span class="string"> OUTPUT_STRIP_TRAILING_WHITESPACE)</span></span><br></pre></td></tr></table></figure><p>这个命令需要在应用程序构建之后执行,因为windeployqt需要检查可执行文件本身以确定需要部署哪些文件。<code>install(CODE)</code>好像是可以执行这个命令的合适地方:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">install</span>(CODE <span class="string">"execute_process(...)"</span>)</span><br></pre></td></tr></table></figure><p>备注:最新版的CMake,在install,execute_process命令中已经支持了生成表达式。</p><p>完整的实现如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">function(windeployqt target directory)</span><br><span class="line"></span><br><span class="line"> # install 从3.12开始支持生成表达式</span><br><span class="line"> install(CODE</span><br><span class="line"> "</span><br><span class="line"> execute_process(</span><br><span class="line"> COMMAND \"${CMAKE_COMMAND}\" -E</span><br><span class="line"> env PATH=\"${QT_BIN_DIR}\" \"${WINDEPLOYQT_EXECUTABLE}\"</span><br><span class="line"> --dry-run</span><br><span class="line"> --no-compiler-runtime</span><br><span class="line"> --no-angle</span><br><span class="line"> --no-opengl-sw</span><br><span class="line"> --list mapping</span><br><span class="line"> \"$<TARGET_FILE:${target}>\"</span><br><span class="line"> OUTPUT_VARIABLE _output</span><br><span class="line"> OUTPUT_STRIP_TRAILING_WHITESPACE</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> # 解析映射</span><br><span class="line"> separate_arguments(_files WINDOWS_COMMAND \${_output})</span><br><span class="line"></span><br><span class="line"> # 拷贝文件</span><br><span class="line"> while(_files)</span><br><span class="line"> list(GET _files 0 _src)</span><br><span class="line"> list(GET _files 1 _dest)</span><br><span class="line"> execute_process(</span><br><span class="line"> COMMAND \"${CMAKE_COMMAND}\" -E</span><br><span class="line"> copy \${_src} \"\${CMAKE_INSTALL_PREFIX}/${directory}/\${_dest}\"</span><br><span class="line"> )</span><br><span class="line"> list(REMOVE_AT _files 0 1)</span><br><span class="line"> endwhile()</span><br><span class="line"> "</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line">endfunction()</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>尽管有些困难,但将windeployqt集成到CPack中也是可以实现的。上面的实现方案可以确保在CPack创建安装程序时包含所有需要的文件。</p><p>一个完整的实现例子<a href="https://github.com/hkeeplearning/using-windeployqt-with-cpack.git">Using windeployqt with cpack</a>。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>-<a href="https://blog.nathanosman.com/2017/11/24/using-windeployqt-with-cpack.html">Using windeployqt with CPack</a></p>]]></content>
<summary type="html"><p>Qt是一个非常优秀的跨平台C++应用程序开发工具包,CMake&#x2F;CPack 是一款非常出色的C++应用程序构建系统(基本上目前也已经成为C++构建系统的标准了)。它们两个可以很好的结合在一起,而且我在很多项目中也已经使用了它们。然而,使用CPack部署包含Qt的项目,却并非易事。这篇文章将描述我是怎么尝试解决这个问题的。</p></summary>
<category term="CPack" scheme="http://hkeepl.github.io/tags/CPack/"/>
<category term="Qt" scheme="http://hkeepl.github.io/tags/Qt/"/>
<category term="windeployqt" scheme="http://hkeepl.github.io/tags/windeployqt/"/>
</entry>
<entry>
<title>使用CMake和VSCode开发C++</title>
<link href="http://hkeepl.github.io/posts/61860"/>
<id>http://hkeepl.github.io/posts/61860</id>
<published>2022-07-16T07:35:21.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>一直以来我都是把 VSCode 当作一个文本编辑器,查看、编辑文本用。突然有一天发现在公司电脑上用 VSCode 编写代码不会被加密,又因为使用 CMake 编译 Qt 工程时需要文件是不加密的(应该是 moc 程序没有加入到公司加密程序列表里,只要头文件中有 <code>Q_OBJECT</code> 的声明,就不行),于是考虑在 VSCode 中编写代码,利用插件生成 VS 工程,编译代码,调试程序等等一些过程。</p><span id="more"></span><h2 id="需要安装的软件"><a href="#需要安装的软件" class="headerlink" title="需要安装的软件"></a>需要安装的软件</h2><ul><li>Visual Studio。当然也可以选择其他的编译器,比如:mingw。</li><li>VSCode</li><li>CMake</li></ul><h2 id="需要安装的-VSCode-插件"><a href="#需要安装的-VSCode-插件" class="headerlink" title="需要安装的 VSCode 插件"></a>需要安装的 VSCode 插件</h2><ul><li>C/C++</li><li>CMake</li><li>CMake Tools</li></ul><h2 id="编写一个最小的-CMake-工程"><a href="#编写一个最小的-CMake-工程" class="headerlink" title="编写一个最小的 CMake 工程"></a>编写一个最小的 CMake 工程</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># CMakeLists.txt</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.18</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">project</span>(HelloWorld CXX)</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(hello-world main.cpp)</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(argc > <span class="number">1</span>) {</span><br><span class="line"> std::cout << argv[<span class="number">1</span>] << std::endl;</span><br><span class="line"> }</span><br><span class="line"> std::cout << <span class="string">"Hello world."</span> << std::endl;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="在-VSCode-中配置程序"><a href="#在-VSCode-中配置程序" class="headerlink" title="在 VSCode 中配置程序"></a>在 VSCode 中配置程序</h2><p>在 VSCode 中按下 CTRL+SHIFT+P,选择 <code>CMake 配置</code>,在弹出的对话框中选择编译器,待CMake配置完成后,输出</p><img data-src="/posts/61860/094f9324f5114b676ea1acfc96ff3783.png" class="" title="配置输出"><p>注意:VSCode 会自动在当前文件夹下新建一个 build 文件夹,里面用于存放 CMake 的配置输出。</p><p>选择状态栏的 <code>Build</code> 按钮,进行编译</p><img data-src="/posts/61860/13b8c09c44ce2c364a316ed04bcb4b0e.png" class="" title="编译输出"><p>成功后,我们就可以运行程序了!</p><p>点击下方的 <code>Launch the selecte target</code>,就可以运行程序了(PS,如果有多个可执行文件,也可以在这里选择其他的目标工程运行)。</p><h2 id="在-VSCode-中调式程序"><a href="#在-VSCode-中调式程序" class="headerlink" title="在 VSCode 中调式程序"></a>在 VSCode 中调式程序</h2><p>本文的重点来了。我们该怎么在 VSCode 中调试程序呢?</p><p>其实,很简单,借助于 CMake Tools 工具,我们只需要在代码中添加断点,点击任务栏的<code>调试(Debug)</code>按钮就可以进行调试了。</p><p>但是,但是,这种调试方式,我们不能输入任何命令行参数!该怎么办呢?</p><p>答案是:使用 VSCode 的调试配置。</p><p>在 .vscode 文件夹下,新建一个 launch.json 文件,并将下面的内容输入到文件中。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="comment">// 使用 IntelliSense 了解相关属性。</span></span><br><span class="line"> <span class="comment">// 悬停以查看现有属性的描述。</span></span><br><span class="line"> <span class="comment">// 欲了解更多信息,请访问:https://go.microsoft.com/fwlink/?linkid=830387</span></span><br><span class="line"> <span class="attr">"version"</span><span class="punctuation">:</span> <span class="string">"0.2.0"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"configurations"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"(msvc) Launch"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"cppvsdbg"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"request"</span><span class="punctuation">:</span> <span class="string">"launch"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"program"</span><span class="punctuation">:</span> <span class="string">"${command:cmake.launchTargetPath}"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"args"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"stopAtEntry"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"cwd"</span><span class="punctuation">:</span> <span class="string">"${workspaceRoot}"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"environment"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"PATH"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"value"</span><span class="punctuation">:</span> <span class="string">"${env:PATH}:${command.cmake.getLaunchTargetDirectory}"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"console"</span><span class="punctuation">:</span> <span class="string">"externalTerminal"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><p>在菜单栏选择 运行->启动调试,便可以调试程序了。</p><p>这里,我尝试输入一个参数,即修改上面配置文件的 <code>args</code>字段:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">"args"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">"You are welcome."</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><p>运行调试程序,输出:</p><img data-src="/posts/61860/d6436e17666588ecb71edd071d15e0cb.png" class="" title="带参数调试输出"><p>终于,过程通了!</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/README.md">CMake Tools for Visual Studio Code documentation</a></li></ul>]]></content>
<summary type="html"><p>一直以来我都是把 VSCode 当作一个文本编辑器,查看、编辑文本用。突然有一天发现在公司电脑上用 VSCode 编写代码不会被加密,又因为使用 CMake 编译 Qt 工程时需要文件是不加密的(应该是 moc 程序没有加入到公司加密程序列表里,只要头文件中有 <code>Q_OBJECT</code> 的声明,就不行),于是考虑在 VSCode 中编写代码,利用插件生成 VS 工程,编译代码,调试程序等等一些过程。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
<category term="CMake" scheme="http://hkeepl.github.io/tags/CMake/"/>
</entry>
<entry>
<title>将博客站点添加到搜索引擎</title>
<link href="http://hkeepl.github.io/posts/43474"/>
<id>http://hkeepl.github.io/posts/43474</id>
<published>2022-07-16T01:37:03.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>既然做了个人博客网站,写了博文,自然是希望能够被搜索引擎检索到的,下面记录了我的设置过程。</p><span id="more"></span><h2 id="安装扩展"><a href="#安装扩展" class="headerlink" title="安装扩展"></a>安装扩展</h2><p>安装用于谷歌和百度收录所需sitemap生成插件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-generator-sitemap</span><br><span class="line">npm install hexo-generator-baidu-sitemap</span><br></pre></td></tr></table></figure><p>在站点配置文件中设置sitemap生成规则,避免产生不必要的文件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sitemap:</span><br><span class="line"> path: sitemap.xml</span><br><span class="line">baidusitemap:</span><br><span class="line"> path: baidusitemap.xml</span><br></pre></td></tr></table></figure><h2 id="将网站添加到搜索引擎"><a href="#将网站添加到搜索引擎" class="headerlink" title="将网站添加到搜索引擎"></a>将网站添加到搜索引擎</h2><h3 id="谷歌设置"><a href="#谷歌设置" class="headerlink" title="谷歌设置"></a>谷歌设置</h3><p>进入<a href="https://search.google.com/search-console/welcome">谷歌搜索设置</a>界面</p><img data-src="/posts/43474/83a84c8e35ce950101cc7362c00f9dbb.png" class="" title="欢迎界面"><p>在<code>网站前缀</code>中输入网址,比如我的<code>https://hkeeplearning.github.io</code>,然后会弹出进行网站验证的页面,这里我选择了推荐的验证方式</p><img data-src="/posts/43474/3eb8622e3e0433dd089ce402ffb8b12d.png" class="" title="验证所有权"><p>下载对应的文件,并将其复制到站点文件夹下的source目录中。注意:因为调用<code>hexo g</code>时文件会重新生成,修改了html的内容,但是这是我们不需要的,所以这里我们打开刚刚复制过来的文件,对文件内容做以下修改,然后保存:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">layout: false</span><br><span class="line">---</span><br><span class="line">google-site-verification: googlee6901d1d3b931cd0.html</span><br></pre></td></tr></table></figure><p>到这里,网站验证通过了,只需要配置站点地图文件,网站就可以被搜索引擎检索了。</p><h3 id="百度设置"><a href="#百度设置" class="headerlink" title="百度设置"></a>百度设置</h3><p>百度搜索设置基本与谷歌搜索设置基本相同。</p><p>进入<a href="https://ziyuan.baidu.com/site/siteadd#/">百度搜索设置</a> 界面</p><img data-src="/posts/43474/c98ba71dd845e76c2f2a669e2808685a.png" class="" title="添加网站到百度搜索"><p>这里也是用将HTML文件上传到网站的验证方式,下载文件,将文件添加到souce文件夹,并且修改文件内容。</p><h2 id="设置站点地图"><a href="#设置站点地图" class="headerlink" title="设置站点地图"></a>设置站点地图</h2><p>hexo本地的配置已经结束了,这里我们重新部署网站</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo g -d</span><br></pre></td></tr></table></figure><h3 id="谷歌设置-1"><a href="#谷歌设置-1" class="headerlink" title="谷歌设置"></a>谷歌设置</h3><p>将站点地图添加到谷歌搜索引擎:</p><img data-src="/posts/43474/29364dc6797c680a5fec86bc48f22c1e.png" class="" title="谷歌搜索引擎"><h3 id="百度设置-1"><a href="#百度设置-1" class="headerlink" title="百度设置"></a>百度设置</h3><p>将站点地图添加到百度搜索引擎:</p><img data-src="/posts/43474/1d499d5a1c0e3a55cf91cfb69bc738e1.png" class="" title="百度搜索引擎">]]></content>
<summary type="html"><p>既然做了个人博客网站,写了博文,自然是希望能够被搜索引擎检索到的,下面记录了我的设置过程。</p></summary>
<category term="博客" scheme="http://hkeepl.github.io/tags/%E5%8D%9A%E5%AE%A2/"/>
</entry>
<entry>
<title>模板显示实例化</title>
<link href="http://hkeepl.github.io/posts/60095"/>
<id>http://hkeepl.github.io/posts/60095</id>
<published>2022-07-14T15:27:06.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>想实现一个模板,但是只能在头文件中声明和实现它,这违反了我们一直遵守的 C++开发规范(声明和实现分离)。模板显示实例化就是这样一种技术,我们可以使用它将模板的声明和实现分离开,唯一的缺点就是我们要将模板类特化为几个类型,但这应该也是 OK 的。</p><span id="more"></span><p>优点:</p><ul><li>去除冗余,一套代码可以创建出很多具有相同方法的不同类</li><li>编译时生成代码,不像虚函数那样付出运行时代价</li><li>可以特化某一类型的特定方法</li></ul><p>但是使用模板有一个明显的缺点:类模板的定义必须放到公开的头文件中。如果在 API 中这样使用模板,一是会暴露内部细节,二是会增加编译时间、致使代码膨胀(每一个包含这个类模板的文件,内联的代码都需要重新编译)。</p><p>可以使用显式实例化将模板的实现隐藏到 cpp 文件中。</p><h2 id="隐式实例化"><a href="#隐式实例化" class="headerlink" title="隐式实例化"></a>隐式实例化</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * my_stack.h</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyStack</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">push</span><span class="params">(T val)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">T <span class="title">pop</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">isEmpty</span><span class="params">()</span> <span class="type">const</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> std::vector<T> stack_;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * my_stack_private.h</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="type">void</span> MyStack<T>::<span class="built_in">push</span>(T val) {</span><br><span class="line"> stack_.<span class="built_in">push_back</span>(val);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line">T MyStack<T>::<span class="built_in">pop</span>(){</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">isEmpty</span>()) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">T</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">auto</span> val = stack_.<span class="built_in">back</span>();</span><br><span class="line"> stack_.<span class="built_in">pop_back</span>();</span><br><span class="line"> <span class="keyword">return</span> val;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="type">bool</span> MyStack<T>::<span class="built_in">isEmpty</span>() <span class="type">const</span>{</span><br><span class="line"> <span class="keyword">return</span> stack_.<span class="built_in">empty</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="显式实例化"><a href="#显式实例化" class="headerlink" title="显式实例化"></a>显式实例化</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * my_stack.h</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyStack</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">push</span><span class="params">(T val)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">T <span class="title">pop</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">isEmpty</span><span class="params">()</span> <span class="type">const</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> std::vector<T> stack_;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> MyStackInt = MyStack<<span class="type">int</span>>;</span><br><span class="line"><span class="keyword">using</span> MyStackFloat = MyStack<<span class="type">float</span>>;</span><br><span class="line"><span class="keyword">using</span> MyStackDouble = MyStack<<span class="type">double</span>>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * my_stack.cpp</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="type">void</span> MyStack<T>::<span class="built_in">push</span>(T val) {</span><br><span class="line"> stack_.<span class="built_in">push_back</span>(val);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line">T MyStack<T>::<span class="built_in">pop</span>(){</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">isEmpty</span>()) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">T</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">auto</span> val = stack_.<span class="built_in">back</span>();</span><br><span class="line"> stack_.<span class="built_in">pop_back</span>();</span><br><span class="line"> <span class="keyword">return</span> val;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="type">bool</span> MyStack<T>::<span class="built_in">isEmpty</span>() <span class="type">const</span>{</span><br><span class="line"> <span class="keyword">return</span> stack_.<span class="built_in">empty</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> <span class="keyword">class</span> <span class="title class_">MyStack</span><<span class="type">int</span>>;</span><br><span class="line"><span class="keyword">template</span> <span class="keyword">class</span> <span class="title class_">MyStack</span><<span class="type">float</span>>;</span><br><span class="line"><span class="keyword">template</span> <span class="keyword">class</span> <span class="title class_">MyStack</span><<span class="type">double</span>>;</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>想实现一个模板,但是只能在头文件中声明和实现它,这违反了我们一直遵守的 C++开发规范(声明和实现分离)。模板显示实例化就是这样一种技术,我们可以使用它将模板的声明和实现分离开,唯一的缺点就是我们要将模板类特化为几个类型,但这应该也是 OK 的。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
</entry>
<entry>
<title>CMake 入门</title>
<link href="http://hkeepl.github.io/posts/38759"/>
<id>http://hkeepl.github.io/posts/38759</id>
<published>2022-07-06T07:35:21.000Z</published>
<updated>2022-08-27T08:46:26.351Z</updated>
<content type="html"><![CDATA[<p>CMake 是一个开源的 C++构建工具生成器,可以很方便的实现跨平台编译,解决 C++库之间的依赖关系。只需要配置 CMakeList.txt 文件就可以实现对 C++源代码构建的控制,而且还是库平台,简直太好用。下面记录了一些常用的 CMake 命令。</p><span id="more"></span><h2 id="命令模式"><a href="#命令模式" class="headerlink" title="命令模式"></a>命令模式</h2><p>平台无关的系统命令,用法示例</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 对 my.txt 文件,生成 md5</span></span><br><span class="line">cmake -E md5sum my.txt</span><br></pre></td></tr></table></figure><p>查看更多命令可以直接输入 cmake -E。</p><h2 id="CTest"><a href="#CTest" class="headerlink" title="CTest"></a>CTest</h2><p><a href="https://www.bookset.io/read/CMake-Cookbook/content-chapter4-4.1-chinese.md">https://www.bookset.io/read/CMake-Cookbook/content-chapter4-4.1-chinese.md</a></p><h2 id="设置-MSVC-编译器编译-utf8-编码格式的源文件"><a href="#设置-MSVC-编译器编译-utf8-编码格式的源文件" class="headerlink" title="设置 MSVC 编译器编译 utf8 编码格式的源文件"></a>设置 MSVC 编译器编译 utf8 编码格式的源文件</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">add_compile_options</span>(<span class="string">"$<$<C_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br><span class="line"><span class="keyword">add_compile_options</span>(<span class="string">"$<$<CXX_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br></pre></td></tr></table></figure><h2 id="禁用特定警告"><a href="#禁用特定警告" class="headerlink" title="禁用特定警告"></a>禁用特定警告</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">add_compile_options</span>(“/wd4819”)</span><br></pre></td></tr></table></figure><h2 id="安装库"><a href="#安装库" class="headerlink" title="安装库"></a>安装库</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>(INSTALL_PROJECT)</span><br><span class="line"><span class="keyword">install</span>(DIRECTORY <span class="string">"${CMAKE_CURRENT_SOURCE_DIR}/include"</span></span><br><span class="line"> DESTINATION <span class="string">"include"</span> OPTIONAL)</span><br><span class="line"><span class="keyword">install</span>(TARGETS <span class="variable">${ARGN}</span></span><br><span class="line"> CONFIGURATIONS Debug</span><br><span class="line"> RUNTIME DESTINATION <span class="string">"bin_debug"</span></span><br><span class="line"> LIBRARY DESTINATION <span class="string">"lib_debug"</span></span><br><span class="line"> ARCHIVE DESTINATION <span class="string">"lib_debug"</span>)</span><br><span class="line"><span class="keyword">install</span>(TARGETS <span class="variable">${ARGN}</span></span><br><span class="line"> CONFIGURATIONS Release</span><br><span class="line"> RUNTIME DESTINATION <span class="string">"bin"</span></span><br><span class="line"> LIBRARY DESTINATION <span class="string">"lib"</span></span><br><span class="line"> ARCHIVE DESTINATION <span class="string">"lib"</span>)</span><br><span class="line"><span class="comment"># install target pdb</span></span><br><span class="line"><span class="keyword">install</span>(FILES $<TARGET_PDB_FILE:<span class="variable">${ARGN}</span>></span><br><span class="line"> CONFIGURATIONS Release</span><br><span class="line"> DESTINATION <span class="string">"bin"</span> OPTIONAL)</span><br><span class="line"><span class="keyword">endfunction</span>()</span><br></pre></td></tr></table></figure><h2 id="导入第三方库"><a href="#导入第三方库" class="headerlink" title="导入第三方库"></a>导入第三方库</h2><p>这里针对已经只有头文件的库,已经编译好的非 CMake 工程库,和 CMake 工程库。</p><h3 id="方式-1"><a href="#方式-1" class="headerlink" title="方式 1"></a>方式 1</h3><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span>(EIGEN3_DIR <span class="string">"path_to_eigen_cmake"</span>)</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">NOT</span> <span class="keyword">EXISTS</span> <span class="string">"${EIGEN3_DIR}"</span>)</span><br><span class="line"><span class="keyword">set</span>(EIGEN3_DIR <span class="string">""</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br><span class="line"><span class="keyword">find_package</span>(EIGEN3 REQUIRED)</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">NOT</span> EIGEN3_FOUND)</span><br><span class="line"><span class="keyword">message</span>(STATUS <span class="string">"Warning: Eigen was not found."</span>)</span><br><span class="line"><span class="keyword">else</span>()</span><br><span class="line"><span class="keyword">message</span>(STATUS <span class="string">"Info: Eigen was found.)</span></span><br><span class="line"><span class="string">include_directories(${EIGEN3_INCLUDE_DIR})</span></span><br><span class="line"><span class="string">endif()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">file(GLOB PLOG_DIR "</span>path/plog*<span class="string">")</span></span><br><span class="line"><span class="string">find_path(WITH_PLOG_INC "</span><span class="keyword">include</span>/plog/Log.h<span class="string">" "</span><span class="variable">${PLOG_DIR}</span><span class="string">" NO_DEFAULT_PATH)</span></span><br><span class="line"><span class="string">if(WITH_PLOG_INC)</span></span><br><span class="line"><span class="string">set(PLOG_INCLUDE_DIRS "</span><span class="variable">${WITH_PLOG_INC}</span>/<span class="keyword">include</span><span class="string">")</span></span><br><span class="line"><span class="string">include_directories(${PLOG_INCLUDE_DIRS})</span></span><br><span class="line"><span class="string">else()</span></span><br><span class="line"><span class="string">message(STATUS "</span>Warning: plog was <span class="keyword">not</span> found.<span class="string">")</span></span><br><span class="line"><span class="string">endif()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">set(Protobuf_SRC_ROOT_FOLDER "</span>path_protobuf_dir<span class="string">")</span></span><br><span class="line"><span class="string">if(NOT EXISTS "</span><span class="variable">${Protobuf_SRC_ROOT_FOLDER}</span><span class="string">")</span></span><br><span class="line"><span class="string">set(Protobuf_SRC_ROOT_FOLDER "</span><span class="string">")</span></span><br><span class="line"><span class="string">endif()</span></span><br><span class="line"><span class="string">find_package(Protobuf_SRC_ROOT_FOLDER REQUIRED)</span></span><br><span class="line"><span class="string">if(NOT Protobuf_SRC_ROOT_FOLDER_FOUND)</span></span><br><span class="line"><span class="string">message(STATUS "</span>Warning: Protobuf was <span class="keyword">not</span> found.<span class="string">")</span></span><br><span class="line"><span class="string">else()</span></span><br><span class="line"><span class="string">message(STATUS "</span>Info: Protobuf was found.)</span><br><span class="line"><span class="keyword">include_directories</span>(<span class="variable">${Protobuf_INCLUDE_DIRS}</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br></pre></td></tr></table></figure><h3 id="方式-2"><a href="#方式-2" class="headerlink" title="方式 2"></a>方式 2</h3><p>使用 CMAKE_PREFIX_PATH</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(WIN32 <span class="keyword">AND</span> MSVC)</span><br><span class="line"><span class="keyword">if</span>(CMAKE_SIZEOF_VOID_P <span class="keyword">EQUAL</span> <span class="number">8</span>)</span><br><span class="line"><span class="keyword">set</span>(QT_PATH <span class="string">"qt_path"</span> CACHE PATH <span class="string">"Qt path"</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br><span class="line"><span class="keyword">set</span>(CMAKE_PREFIX_PATH <span class="string">"${QT_PATH}"</span>)</span><br><span class="line">mark_as_advance(QT_PATH)</span><br><span class="line"><span class="keyword">endif</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">find_package</span>(Protobuf REQUIRED)</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">NOT</span> Protobuf_FOUND)</span><br><span class="line"><span class="keyword">message</span>(STATUS <span class="string">"Warning: Protobuf was not found."</span>)</span><br><span class="line"><span class="keyword">else</span>()</span><br><span class="line"><span class="keyword">message</span>(STATUS <span class="string">"Info: Protobuf was found."</span>)</span><br><span class="line"><span class="keyword">include_directories</span>(<span class="variable">${Protobuf_INCLUDE_DIRS}</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br></pre></td></tr></table></figure><h2 id="Qt-翻译文件"><a href="#Qt-翻译文件" class="headerlink" title="Qt 翻译文件"></a>Qt 翻译文件</h2><p><a href="https://gitlab.kitware.com/cmake/cmake/-/issues/21549">https://gitlab.kitware.com/cmake/cmake/-/issues/21549</a></p><h2 id="MACRO-和-FUNCTION"><a href="#MACRO-和-FUNCTION" class="headerlink" title="MACRO 和 FUNCTION"></a>MACRO 和 FUNCTION</h2><p><a href="https://blog.csdn.net/weixin_34121282/article/details/87972772">https://blog.csdn.net/weixin_34121282/article/details/87972772</a></p><p><a href="https://www.jianshu.com/p/6be3b104ab70">https://www.jianshu.com/p/6be3b104ab70</a></p><h3 id="共同点"><a href="#共同点" class="headerlink" title="共同点"></a>共同点</h3><p>形式基本相同。</p><p>marco 形式如下:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">macro</span>(<name> [arg1 [arg2 [arg3 ...]]])</span><br><span class="line">COMMAND1(ARGS ...)</span><br><span class="line">COMMAND2(ARGS ...)</span><br><span class="line"><span class="keyword">endmacro</span>()</span><br></pre></td></tr></table></figure><p>function 形式如下:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>(<name> [arg1 [arg2 [arg3 ...]]])</span><br><span class="line">COMMAND1(ARGS ...)</span><br><span class="line">COMMAND2(ARGS ...)</span><br><span class="line"><span class="keyword">endfunction</span>()</span><br></pre></td></tr></table></figure><p>变量的引用:</p><table><thead><tr><th>变量</th><th>说明</th></tr></thead><tbody><tr><td>ARGV#</td><td>同上</td></tr><tr><td>ARGV</td><td>所有定义时要求传入的参数</td></tr><tr><td>ARGN</td><td>定义时要求输入的参数以外的参数,比如定义时要求输入 1 个参数,实际输入了 3 个,那么后面两个参数保存在 ARGN 中</td></tr><tr><td>ARGC</td><td>传入的实际参数个数</td></tr></tbody></table><h2 id="设置构建-toolset"><a href="#设置构建-toolset" class="headerlink" title="设置构建 toolset"></a>设置构建 toolset</h2><p>在高版本的 Visual Studio 可以使用低版本的 toolset 进行编译,比如,vs2019,安装了 vs2017 的构建工具和 sdk 后可以使用 vs2017 构建 cmake 项目。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 设置 generator</span><br><span class="line">-G "Visual Studio 15 2017" </span><br><span class="line"># 设置 toolset</span><br><span class="line">-T v141</span><br></pre></td></tr></table></figure><h2 id="设置输出目录"><a href="#设置输出目录" class="headerlink" title="设置输出目录"></a>设置输出目录</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span>(CMAKE_RUNTIME_OUTPUT_DIRECTORY <span class="string">"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}"</span>)</span><br><span class="line"><span class="keyword">set</span>(CMAKE_LIBRARY_OUTPUT_DIRECTORY <span class="string">"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}"</span>)</span><br><span class="line"><span class="keyword">set</span>(CMAKE_ARCHIVE_OUTPUT_DIRECTORY <span class="string">"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}"</span>)</span><br></pre></td></tr></table></figure><h2 id="设置工程调试的工作目录"><a href="#设置工程调试的工作目录" class="headerlink" title="设置工程调试的工作目录"></a>设置工程调试的工作目录</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">VS_DEBUGGER_WORKING_DIRECTORY</span><br></pre></td></tr></table></figure><h2 id="设置工程属性"><a href="#设置工程属性" class="headerlink" title="设置工程属性"></a>设置工程属性</h2><h2 id="输出文件名"><a href="#输出文件名" class="headerlink" title="输出文件名"></a>输出文件名</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set_target_properties</span>(LibraryA PROPERTIES OUTPUT_NAME <span class="string">"my_LibraryA"</span>)</span><br></pre></td></tr></table></figure><h2 id="预处理器定义"><a href="#预处理器定义" class="headerlink" title="预处理器定义"></a>预处理器定义</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set_target_properties</span>(LibraryA PROPERTIES COMPILE_DEFINITIONS <span class="string">"LibraryA_EXPORTS"</span>)</span><br></pre></td></tr></table></figure><h3 id="工程分组"><a href="#工程分组" class="headerlink" title="工程分组"></a>工程分组</h3><p>根目录设置:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set_property</span>(GLOBAL PROPERTY USE_FOLDERS <span class="keyword">ON</span>)</span><br></pre></td></tr></table></figure><p>每个分组下工程设置:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set_target_properties</span>(LibraryA PROPERTIES FOLDER <span class="string">"Utilities"</span>)</span><br><span class="line"><span class="keyword">set_target_properties</span>(LibraryB PROPERTIES FOLDER <span class="string">"Utilities"</span>)</span><br></pre></td></tr></table></figure><h2 id="源文件分组"><a href="#源文件分组" class="headerlink" title="源文件分组"></a>源文件分组</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">source_group</span>(<span class="string">"game\\entitysystem\\components"</span> FILES <span class="variable">${components_SRC}</span>) </span><br></pre></td></tr></table></figure><h2 id="设置-Windows-Qt-工程不弹出命令行窗口"><a href="#设置-Windows-Qt-工程不弹出命令行窗口" class="headerlink" title="设置 Windows Qt 工程不弹出命令行窗口"></a>设置 Windows Qt 工程不弹出命令行窗口</h2><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#--------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"># Hide the console window in visual studio projects</span></span><br><span class="line"><span class="comment">#--------------------------------------------------------------------</span></span><br><span class="line"><span class="keyword">if</span>(MSVC)</span><br><span class="line"> <span class="keyword">set</span>(CMAKE_EXE_LINKER_FLAGS <span class="string">"${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup"</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">#--------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"># Hide the console window in visual studio projects - Release</span></span><br><span class="line"><span class="comment">#--------------------------------------------------------------------</span></span><br><span class="line"><span class="keyword">if</span>(MSVC)</span><br><span class="line"> <span class="keyword">set</span>(CMAKE_EXE_LINKER_FLAGS_RELEASE <span class="string">"${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup"</span>)</span><br><span class="line"><span class="keyword">endif</span>()</span><br></pre></td></tr></table></figure><h2 id="INCLUDE-DIRECTORIES作用域"><a href="#INCLUDE-DIRECTORIES作用域" class="headerlink" title="INCLUDE_DIRECTORIES作用域"></a><code>INCLUDE_DIRECTORIES</code>作用域</h2><p>The include directories are added to the INCLUDE_DIRECTORIES directory property for <strong>the current CMakeLists file</strong>. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file.</p><h2 id="set用法"><a href="#set用法" class="headerlink" title="set用法"></a><code>set</code>用法</h2><h3 id="set赋值给一般变量"><a href="#set赋值给一般变量" class="headerlink" title="set赋值给一般变量"></a><code>set</code>赋值给一般变量</h3><p>仅在所在的作用域起作用。除非后面使用 PARENT_SCOPE。举例</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// foo 作用域为当前作用域</span><br><span class="line"><span class="keyword">set</span>(foo <span class="string">"X"</span>)</span><br><span class="line"></span><br><span class="line">// foo 作用域是当前文件的上一目录的 CMakeList</span><br><span class="line"><span class="keyword">set</span>(foo <span class="string">"x"</span> PARENT_SCOPE)</span><br></pre></td></tr></table></figure><h3 id="set赋值给缓存变量"><a href="#set赋值给缓存变量" class="headerlink" title="set赋值给缓存变量"></a><code>set</code>赋值给缓存变量</h3><p>第一次运行 cmake 时,这些变量缓存到 CMakeCache.txt 中,在整个 cmake 运行过程中都可以起作用。</p><p>当使用 CACHE 时,且缓存中没有该变量时,变量被创建并且存入缓存中,如果原缓存中有该变量,也不会改变原缓存中该变量的值,除非后面使用 FORCE。</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 原缓存中没有 foo,则将 foo 赋值为 x,且存入缓存</span><br><span class="line">// 原缓存中有 foo,则不做改变</span><br><span class="line"><span class="keyword">set</span>(foo <span class="string">"x"</span> CACHE <type> <docstring>)</span><br><span class="line"></span><br><span class="line">// 即使原缓存中存在 foo,也会重新设置 foo</span><br><span class="line"><span class="keyword">set</span>(foo <span class="string">"x"</span> CACHE <type> <docstring> FORCE)</span><br></pre></td></tr></table></figure><p>使用 CACHE 时,要设定<code><type></code>和<code>docstring</code>。</p><table><thead><tr><th>type</th><th>description</th></tr></thead><tbody><tr><td>FILEPATH</td><td>File chooser dialog.</td></tr><tr><td>PATH</td><td>Directory chooser dialog.</td></tr><tr><td>STRING</td><td>Arbitrary string.</td></tr><tr><td>BOOL</td><td>Boolean ON/OFF checkbox.</td></tr><tr><td>INTERNAL</td><td>No GUI entry (used for persistent variables).</td></tr></tbody></table><h3 id="可以通过-CMake-变量声明另一个变量"><a href="#可以通过-CMake-变量声明另一个变量" class="headerlink" title="可以通过 CMake 变量声明另一个变量"></a>可以通过 CMake 变量声明另一个变量</h3><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span>(<span class="variable">${macroparam}</span>_LOCATION “”)</span><br></pre></td></tr></table></figure><p>在 CMakeList 文件中使用</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">message</span>(STATUS <span class="variable">${${macroparam}</span>_LOCATION})</span><br></pre></td></tr></table></figure><h3 id="设置后缀"><a href="#设置后缀" class="headerlink" title="设置后缀"></a>设置后缀</h3><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span>(CMAKE_DEBUG_POSTFIX <span class="string">"_d"</span>)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>CMake 是一个开源的 C++构建工具生成器,可以很方便的实现跨平台编译,解决 C++库之间的依赖关系。只需要配置 CMakeList.txt 文件就可以实现对 C++源代码构建的控制,而且还是库平台,简直太好用。下面记录了一些常用的 CMake 命令。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
<category term="CMake" scheme="http://hkeepl.github.io/tags/CMake/"/>
</entry>
<entry>
<title>常用设计模式</title>
<link href="http://hkeepl.github.io/posts/14845"/>
<id>http://hkeepl.github.io/posts/14845</id>
<published>2022-05-04T08:45:24.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>设计模式是编码的一种经验总结,通过设计模式我们可以实现通用性好,易于扩展,方便维护的接口。</p><span id="more"></span><h2 id="设计模式"><a href="#设计模式" class="headerlink" title="设计模式"></a>设计模式</h2><h3 id="Pimpl惯用法"><a href="#Pimpl惯用法" class="headerlink" title="Pimpl惯用法"></a><code>Pimpl</code>惯用法</h3><p>隐藏内部细节。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// autotimer.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(_WIN32) || defined(_WIN64)</span></span><br><span class="line"><span class="meta"># <span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/time.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">IMG_BEGIN_NAMESPACE</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AutoTimer</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">AutoTimer</span>();</span><br><span class="line"> ~<span class="built_in">AutoTimer</span>();</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="function"><span class="type">double</span> <span class="title">GetElapsed</span><span class="params">()</span> <span class="type">const</span></span>;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(_WIN32) || defined(_WIN64)</span></span><br><span class="line">DWORD mStartTime;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">timeval</span> mStartTime;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> </span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">IMG_END_NAMESPACE</span><br></pre></td></tr></table></figure><p>实现这个类的目的只是为了获取对象从构造到销毁之间的运行时间,与程序在是什么平台上跑完全没有关系吧。在这个头文件中暴露了太多的细节,破坏了接口的简洁性。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// autotimer.h</span></span><br><span class="line">IMG_BEGIN_NAMESPACE</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><memory></span></span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AutoTimer</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">AutoTimer</span>();</span><br><span class="line"> ~<span class="built_in">AutoTimer</span>();</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">class</span> <span class="title class_">Impl</span>; <span class="comment">//! 声明为私有,在CPP文件里的其他类或者自由函数不能访问Impl</span></span><br><span class="line"> Impl *mImpl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">IMG_END_NAMESPACE</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// IMG_SYSTEM_STATE_HPP_H_</span></span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// autotimer.cpp</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(_WIN32) || defined(_WIN64)</span></span><br><span class="line"><span class="meta"># <span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/time.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line">IMG_BEGIN_NAMESPACE</span><br><span class="line"> </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AutoTimer</span>::Impl</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="type">double</span> <span class="title">GetElapsed</span><span class="params">()</span> <span class="type">const</span></span>;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(_WIN32) || defined(_WIN64)</span></span><br><span class="line">DWORD mStartTime;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">timeval</span> mStartTime;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> </span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">AutoTimer::<span class="built_in">AutoTimer</span>() : <span class="built_in">mImpl</span>(<span class="keyword">new</span> AutoTimer::<span class="built_in">Impl</span>())</span><br><span class="line">{</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(_WIN32) || defined(_WIN64) </span></span><br><span class="line"> mImpl->mStartTime = <span class="built_in">GetTickCount</span>();</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="built_in">gettimeofday</span>(&(mImpl->mStartTime), <span class="literal">NULL</span>); </span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">}</span><br><span class="line">AutoTimer::~<span class="built_in">AutoTimer</span>()</span><br><span class="line">{</span><br><span class="line"> std::cout << <span class="string">"Elapsed time: "</span> << mImpl-><span class="built_in">GetElapsed</span>() << std::endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">IMG_END_NAMESPACE</span><br></pre></td></tr></table></figure><p>那么,什么样的函数或者数据成员应该放到Implementation类中呢?</p><ul><li>仅私有成员变量</li><li>私有成员变量和方法</li><li>公有类的所有方法,其中公有方法只是对<code>Impl</code>类中的等价方法进行简单的包装</li></ul><p>多倾向与采用在<code>Impl</code>类中放置<strong>私有成员变量和方法</strong>的逻辑。</p><p>Note:</p><p>使用<code>Pimp</code>惯用法时,应采用私有内嵌实现类,以更好地隐藏细节。只有在<code>.cpp</code>文件中其他类或者自由函数必须访问<code>Impl</code>成员时,才应采用公有内嵌类。</p><p>注意:<strong>复制语义</strong>,常使用<strong>智能指针</strong>建立<code>Impl</code>类的实例。</p><h3 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h3><p>只创建一个对象实例。</p><ul><li>私有化默认构造函数</li><li>私有化赋值和赋值构造函数</li><li>私有析构函数</li><li>返回指针或者引用</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Singleton</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">static</span> Singleton &<span class="title">GetInstance</span><span class="params">()</span></span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">Singleton</span>();</span><br><span class="line"> ~<span class="built_in">Singleton</span>();</span><br><span class="line"> <span class="built_in">Singleton</span>(<span class="type">const</span> Singleton &);</span><br><span class="line"> <span class="type">const</span> Singleton &<span class="keyword">operator</span>=(<span class="type">const</span> Singleton &);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>不同编译单元中的非局部静态对象的初始化顺序是未定义的</p></blockquote><p>非局部对象是指在函数之外声明的对象,为了保证初始化顺序,在类的方法中创建静态变量。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">Singleton &<span class="title">Singleton::GetInstance</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">static</span> Singleton instance;</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意:上述实现不是线程安全的! 通常的做法是加互斥锁。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> Mutex mutex;</span><br><span class="line"><span class="function">Singleton &<span class="title">Singleton::GetInstance</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">ScopedLock <span class="title">lock</span><span class="params">(&mutex)</span></span>;</span><br><span class="line"> <span class="type">static</span> Singleton instance;</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>缺点:由于每次调用<code>GetInstance()</code>函数时都会尝试获取锁,介绍调用时都会释放锁,这样的方法开销大。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> Mutex mutex;</span><br><span class="line"><span class="function">Singleton &<span class="title">Singleton::GetInstance</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">static</span> Singleton *instance = <span class="literal">nullptr</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">nullptr</span> == instance)</span><br><span class="line"> {</span><br><span class="line"> <span class="function">ScopedLock <span class="title">lock</span><span class="params">(&mutex)</span></span>;</span><br><span class="line"> <span class="keyword">if</span>(<span class="literal">nullptr</span> == instance)</span><br><span class="line"> {</span><br><span class="line"> instance = <span class="keyword">new</span> <span class="built_in">Singleton</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> *instance;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>静态初始化:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">Singleton &<span class="title">Singleton::GetInstance</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">static</span> Singleton instance;</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line">}</span><br><span class="line"><span class="type">static</span> Singleton &ins = Singleton::<span class="built_in">GetInstance</span>();</span><br></pre></td></tr></table></figure><p>显式API初始化,在程序已启动便首先调用<code>APIInitialize</code>函数:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> std::mutex mut;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">APIInitialize</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">std::lock_guard<std::mutex> <span class="title">lock</span><span class="params">(mut)</span></span>;</span><br><span class="line"> Singleton::<span class="built_in">GetInstance</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>扩展,单一状态模式</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Monostate</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">GetTheAnswer</span><span class="params">()</span> <span class="type">const</span> </span>{ <span class="keyword">return</span> m_s_answer;}</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> m_s_answer;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> Monstate::m_s_answer = <span class="number">16</span>;</span><br></pre></td></tr></table></figure><h3 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h3><p>隐藏派生类实现细节。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// renderfactory.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"render.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">RenderFactory</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">IRender *<span class="title">CreateRender</span><span class="params">(<span class="type">const</span> std::string &type)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// renderfactory.cpp</span></span><br><span class="line"><span class="comment">// 假设已经存在`OpenGLRender`, `DirectXRender`, 和 `MesaRender`三个派生类</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"renderfactory.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"openglreder.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"directxrender.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"mesarender.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">IRender *<span class="title">RenderFactory::CreateRender</span><span class="params">(<span class="type">const</span> std::string &type)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(type == <span class="string">"opengl"</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">OpenGLRender</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(type == <span class="string">"directx"</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">DirectXRender</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(type == <span class="string">"mesa"</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">MesaRender</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>该类的缺陷是:包含了可用的派生类的硬编码信息。</p><p>扩展工厂示例:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// renderfacory.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"render.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><map></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">RenderFactory</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="keyword">typedef</span> IRender *(*CreateCallback)();</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">RegisterRender</span><span class="params">(<span class="type">const</span> std::string &type, CreateCallback cb)</span></span>;</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">UnRegisterReder</span><span class="params">(<span class="type">const</span> std::string &type)</span></span>;</span><br><span class="line"> <span class="function"><span class="type">static</span> IRender *<span class="title">CreateRender</span><span class="params">(<span class="type">const</span> std::string &type)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">typedef</span> std::map<std::string, CreateCallback> CallbackMap</span><br><span class="line"> <span class="type">static</span> CallbackMap m_renders;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// renderfactory.cpp</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"randerfactory.h"</span></span></span><br><span class="line">RenderFactory::CallBackMap RenderFactory::m_renders;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">RenderFactory::RegisterRender</span><span class="params">(<span class="type">const</span> std::string &type, CreateCallback cb)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> m_render[type] = cb;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">RenderFactory::UnRegisterReder</span><span class="params">(<span class="type">const</span> std::string &type)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(m_render.<span class="built_in">find</span>(type) != m_render.<span class="built_in">end</span>())</span><br><span class="line"> {</span><br><span class="line"> m_render.<span class="built_in">erase</span>(type);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function">IRender *<span class="title">RenderFactory::CreateRender</span><span class="params">(<span class="type">const</span> std::string &type)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> CallbackMap::iterator it = m_render.<span class="built_in">find</span>(type);</span><br><span class="line"> <span class="keyword">if</span>(it != m_render.<span class="built_in">end</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> (it->second)();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">UserRender</span>: <span class="keyword">public</span> IRender</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">~<span class="built_in">UserRender</span>(){}</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Render</span><span class="params">()</span> </span>{std::cout << <span class="string">"User render\n"</span>;}</span><br><span class="line"><span class="function"><span class="type">static</span> IRender *<span class="title">Create</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">UserRender</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> RenderFactory::<span class="built_in">ReginsterRender</span>(<span class="string">"user"</span>, UserRender::Create);</span><br><span class="line"> IRender *r = RenderFactory::<span class="built_in">CreateRender</span>(<span class="string">"user"</span>);</span><br><span class="line"> r-><span class="built_in">Render</span>();</span><br><span class="line"> <span class="keyword">delete</span> r;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="代理、适配器和外观(包装器模式)"><a href="#代理、适配器和外观(包装器模式)" class="headerlink" title="代理、适配器和外观(包装器模式)"></a>代理、适配器和外观(包装器模式)</h3><p>结构化设计模式。按照包装器层与原始接口的差异递增程度,依次介绍以下几种:代理、适配器、外观。</p><ul><li><strong>代理模式</strong></li></ul><p>为另一个类提供了一对一的转发接口:调用代理类的FunctionA()将导致调用原始类中的FunctionA()。也就是说,代理类和原始类有相同的接口。它可以被认为是一个单一组件包装器。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Proxy</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">Proxy</span>() : <span class="built_in">m_orig</span>(<span class="keyword">new</span> <span class="built_in">Original</span>())</span><br><span class="line"> {</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> ~<span class="built_in">Proxy</span>() </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">delete</span> m_orig;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">DoSomething</span><span class="params">(<span class="type">int</span> value)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> m_orig-><span class="built_in">DoSomething</span>(value);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">Proxy</span>(<span class="type">const</span> Proxy &);</span><br><span class="line"> <span class="type">const</span> Proxy &<span class="keyword">operator</span>=(<span class="type">const</span> Proxy &);</span><br><span class="line"> </span><br><span class="line"> Original *m_orig;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>另一种方案,增加一个共享的虚接口。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">IOriginal</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="type">bool</span> <span class="title">DoSomething</span><span class="params">(<span class="type">int</span> value)</span> </span>= <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Original</span> : <span class="keyword">public</span> IOriginal</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">DoSomething</span><span class="params">(<span class="type">int</span> value)</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Proxy</span> : <span class="keyword">public</span> IOriginal</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="built_in">Proxy</span>() : <span class="built_in">m_orig</span>(<span class="keyword">new</span> <span class="built_in">Original</span>())</span><br><span class="line">{}</span><br><span class="line">~<span class="built_in">Proxy</span>()</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">delete</span> m_orig;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">DoSomething</span><span class="params">(<span class="type">int</span> value)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> m_orig-><span class="built_in">DoSomething</span>(value);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="built_in">Proxy</span>(<span class="type">const</span> Proxy &);</span><br><span class="line"> <span class="type">const</span> Proxy &<span class="keyword">operator</span>=(<span class="type">const</span> Proxy &);</span><br><span class="line"> </span><br><span class="line"> Original *m_orig;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>适配器模式</strong></li></ul><p>将一个类的接口转换为一个兼容的但不相同的接口。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">RectangleAdapter</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">RectangleAdapter</span>(): <span class="built_in">m_rect</span>(<span class="keyword">new</span> <span class="built_in">Rectangle</span>())</span><br><span class="line"> {}</span><br><span class="line"> ~<span class="built_in">RectangleAdapter</span>()</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">delete</span> m_rect;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Set</span><span class="params">(<span class="type">float</span> x1, <span class="type">float</span> y1, <span class="type">float</span> x2, <span class="type">float</span> y2)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="type">float</span> w = x2 - x1;</span><br><span class="line"> <span class="type">float</span> h = y2 - y1;</span><br><span class="line"> <span class="type">float</span> cx = w / <span class="number">2.0f</span> + x1;</span><br><span class="line"> <span class="type">float</span> cy = h / <span class="number">2.0f</span> + y1;</span><br><span class="line"> m_rect-><span class="built_in">setDimensions</span>(cx, cy, w, h);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">RectangleAdapter</span>(<span class="type">const</span> RectangleAdapter &);</span><br><span class="line"> <span class="type">const</span> RectangleAdapter &<span class="keyword">operator</span>=(<span class="type">const</span> RectangleAdapter &);</span><br><span class="line"> </span><br><span class="line"> Rectangle *m_rect;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>外观模式</strong></li></ul><p>为一组类提供简化的接口。外观模式和适配器模式的区别是,外观模式简化了类的结构,而适配器模式仍然保持相同的类结构。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Taxi</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">BookTaxi</span><span class="params">(<span class="type">int</span> people, <span class="type">time_t</span> pickupTime)</span></span>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Restaurant</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">ReserveTable</span><span class="params">(<span class="type">int</span> people, <span class="type">time_t</span> arrivalTime)</span></span>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Theater</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">timet_t</span> <span class="title">GetShowTime</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="type">bool</span> <span class="title">ReserveSeats</span><span class="params">(<span class="type">int</span> people, <span class="type">int</span> tier)</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ConciergeFacade</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="keyword">enum</span> <span class="title class_">ERestaurant</span></span><br><span class="line"> {</span><br><span class="line"> RESTAURANT_YES,</span><br><span class="line"> RESTAURANT_NO,</span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">enum</span> <span class="title class_">ETaxi</span></span><br><span class="line"> {</span><br><span class="line"> TAXI_YES,</span><br><span class="line"> TAXI_NO,</span><br><span class="line"> };</span><br><span class="line"> <span class="function"><span class="type">time_t</span> <span class="title">BookShow</span><span class="params">(<span class="type">int</span> people, ERestaurant addRestaurant, ETaxi addTaxi)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="观察者"><a href="#观察者" class="headerlink" title="观察者"></a>观察者</h3><p>定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在主题对象状态发生变化时,会通知所有的观察者。</p><p><a href="https://github.com/hkeeplearning/LearningCpp/tree/master/ObserverPattern">示例</a></p><h3 id="装饰模式"><a href="#装饰模式" class="headerlink" title="装饰模式"></a>装饰模式</h3><p>装饰模式以对客户透明的方式动态地给一个对象附加更多的责任,扩展对象的功能。</p><p><a href="https://github.com/hkeeplearning/LearningCpp/tree/master/DecoratorPattern">示例</a></p>]]></content>
<summary type="html"><p>设计模式是编码的一种经验总结,通过设计模式我们可以实现通用性好,易于扩展,方便维护的接口。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
<category term="设计模式" scheme="http://hkeepl.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
</entry>
<entry>
<title>C++代码设计原则</title>
<link href="http://hkeepl.github.io/posts/35242"/>
<id>http://hkeepl.github.io/posts/35242</id>
<published>2020-06-30T01:11:48.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>列举了代码编写的一些原则,遵守这些原则可以使大型项目的开发易于维护。</p><span id="more"></span><h2 id="全局名字空间"><a href="#全局名字空间" class="headerlink" title="全局名字空间"></a>全局名字空间</h2><h3 id="全局数据"><a href="#全局数据" class="headerlink" title="全局数据"></a>全局数据</h3><p>将全局变量非全局化:</p><ol><li>将所有的全局变量放入一个结构中</li><li>然后将他们私有化并添加静态访问函数</li></ol><p>如我们有下面的全局变量:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> size;</span><br><span class="line"><span class="type">double</span> scale;</span><br><span class="line"><span class="type">const</span> <span class="type">char</span> *system;</span><br></pre></td></tr></table></figure><p>可以这样修改:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 头文件中这样声明,记得要在源文件中定义这些静态成员变量</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Global</span> {</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> s_size;</span><br><span class="line"> <span class="type">static</span> <span class="type">double</span> s_scale;</span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> *s_system;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但是,直接访问成员变量的方式会使维护大型系统的成本极为昂贵。而且,如果<code>s_size</code>是基于另外两个更原始的值计算得到的 (<code>s_width</code>, <code>s_height</code>),直接暴露<code>s_size</code>也是不好的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 单一状态</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Global</span> {</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> s_size;</span><br><span class="line"> <span class="type">static</span> <span class="type">double</span> s_scale;</span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> *s_system;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">Global</span>();</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="comment">// MANIPULAORS</span></span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">setSize</span><span class="params">(<span class="type">int</span> size)</span> </span>{s_size = size;}</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">setScale</span><span class="params">(<span class="type">double</span> scale)</span> </span>{s_scale = scale;}</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">setSyetem</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *system)</span> </span>{s_system = system;}</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// ACCESSORS</span></span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">getSize</span><span class="params">()</span> </span>{<span class="keyword">return</span> s_size;}</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">double</span> <span class="title">getScale</span><span class="params">()</span> </span>{<span class="keyword">return</span> s_scale;}</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">const</span> <span class="type">char</span> *<span class="title">getSystem</span><span class="params">()</span> </span>{<span class="keyword">return</span> s_system;}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="自由函数"><a href="#自由函数" class="headerlink" title="自由函数"></a>自由函数</h3><blockquote><p>避免在.h文件的文件作用域内使用自由函数(运算符函数除外);</p><p>在.c文件中避免使用带有外部链接的自由函数(包括运算符函数)</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// bad</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">getMonitorResolution</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setSystemScale</span><span class="params">(<span class="type">double</span> scaleFactor)</span></span>;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">isPasswordCorrect</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *usr, cong <span class="type">char</span> *pwd)</span></span>;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// fine</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">SysUtil</span> {</span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">getMonitorResolution</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">setSystemScale</span><span class="params">(<span class="type">double</span> scaleFactor)</span></span>;</span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">isPasswordCorrect</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *usr, cong <span class="type">char</span> *pwd)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="枚举,typedef和常量数据"><a href="#枚举,typedef和常量数据" class="headerlink" title="枚举,typedef和常量数据"></a>枚举,typedef和常量数据</h3><p>枚举类型,typedef和文件作用域常量数据都有内部链接,人们经常在头文件的问阿金作用域内声明常量,枚举或typedef。但,这是错误的!</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// bad</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// paint.h</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Color</span> {RED, GREEN, BLUE, ORANGE, YELLOW};</span><br><span class="line"></span><br><span class="line"><span class="comment">// juice.h</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Fruit</span> {APPLE, ORANGE, GRAPE, CRANBERRY};</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当这样包含时就会发生错误, ORANGE 有二义性</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"paint.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"juice.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"picture.h"</span></span></span><br></pre></td></tr></table></figure><p>如果在单独的类中定义这两个枚举,我们可以很容易地使用作用域解析消除二义性问题</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Paint</span> {</span><br><span class="line"> <span class="keyword">enum</span> <span class="title class_">Color</span> {RED, GREEN, BLUE, ORANGE, YELLOW};</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Juice</span> {</span><br><span class="line"> <span class="keyword">enum</span> <span class="title class_">Fruit</span> {APPLE, ORANGE, GRAPE, CRANBERRY};</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>基于类似的原因,typedef和常量数据,也可以放在头文件的类作用域内。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// array.h</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">String</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Array</span> {</span><br><span class="line"> <span class="keyword">enum</span> {DEFAULT_SIZE = <span class="number">100</span>};</span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> <span class="type">double</span> DEFAULT_VALUE;</span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> String DEFAULT_NAME;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// array.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"array.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"str.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">double</span> Array::DEFAULT_VALUE = <span class="number">0.0</span>;</span><br><span class="line">String Array::DEFAULT_NAME = <span class="string">"111"</span>;</span><br></pre></td></tr></table></figure><h3 id="预处理宏"><a href="#预处理宏" class="headerlink" title="预处理宏"></a>预处理宏</h3><p>好的地方:</p><ol><li>包含卫哨</li><li>在.c文件中(用于可移植或调试)</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// bad</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// theircode.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GOOD 0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ourcode.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"theircode.h"</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">OurClass::aFunction</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">enum</span> {BAD = <span class="number">-1</span>, GOOD = <span class="number">0</span>} status = GOOD;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> status;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>该段代码会:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">OurClass::aFunction</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">enum</span> {BAD = <span class="number">-1</span>, <span class="number">0</span> = <span class="number">0</span>} status = <span class="number">0</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> status;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因此,就是弹出Syntax Error(语法错误)。</p><h3 id="头文件中的名字"><a href="#头文件中的名字" class="headerlink" title="头文件中的名字"></a>头文件中的名字</h3><blockquote><p>在一个.h文件作用域中,只应该声明类,结构体,联合体,和自由运算符函数</p><p>在.h文件作用域中只应该定义类,结构体,联合体的内联成员函数和自由运算符函数</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PI 3.1415926<span class="comment">// avoid</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MIN(X, Y) ((X) < (Y)) ? (X) : (Y)<span class="comment">// avoid</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DriverInit</span>;<span class="comment">// fine</span></span><br><span class="line"><span class="keyword">union</span> <span class="title class_">Uaw</span>;<span class="comment">// fine</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="type">int</span> globalVariable;<span class="comment">// avoid</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> fileScopeVariable;<span class="comment">// avoid</span></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> BUFFER_SIZE = <span class="number">256</span>;<span class="comment">// avoid</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Boolean</span> {ZERO, ONE};<span class="comment">// avoid</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> BigInt;<span class="comment">// avoid</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Driver</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Color</span></span><br><span class="line">{</span><br><span class="line">RED,</span><br><span class="line">GREEN,</span><br><span class="line">};<span class="comment">// fine</span></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">int</span> <span class="params">(Driver::*PMF)</span><span class="params">()</span></span>;<span class="comment">// fine</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> s_cont;<span class="comment">// fine</span></span><br><span class="line"><span class="type">int</span> d_size;<span class="comment">// fine</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Pnt</span> {</span><br><span class="line"><span class="type">short</span> <span class="type">int</span> x, y;</span><br><span class="line"><span class="built_in">Pnt</span>(<span class="type">int</span> x_, <span class="type">int</span> y_) : </span><br><span class="line"><span class="built_in">x</span>(x_), <span class="built_in">y</span>(y_) {}</span><br><span class="line">};<span class="comment">// fine</span></span><br><span class="line"><span class="keyword">friend</span> DriverInit;<span class="comment">// fine</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">round</span><span class="params">(<span class="type">double</span> d)</span></span>;<span class="comment">// fine</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setSize</span><span class="params">(<span class="type">int</span> size)</span></span>;<span class="comment">// fine</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">cmp</span><span class="params">(<span class="type">const</span> Driver &)</span> <span class="type">const</span></span>;<span class="comment">// fine</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="keyword">class</span> <span class="title class_">DriverInit</span></span><br><span class="line">{</span><br><span class="line"><span class="comment">// ....</span></span><br><span class="line">} driverInit;<span class="comment">// special case</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">min</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span></span>;<span class="comment">// avoid</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">max</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> x > y ? x : y;</span><br><span class="line">}<span class="comment">// avoid</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> </span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Driver::setSize</span><span class="params">(<span class="type">int</span> size)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">d_size = size;</span><br><span class="line">}<span class="comment">// fine</span></span><br><span class="line"></span><br><span class="line">ostream &<span class="keyword">operator</span><<(ostream &o, <span class="type">const</span> Driver &d);</span><br><span class="line"><span class="comment">// fine</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="包含卫哨"><a href="#包含卫哨" class="headerlink" title="包含卫哨"></a>包含卫哨</h3>]]></content>
<summary type="html"><p>列举了代码编写的一些原则,遵守这些原则可以使大型项目的开发易于维护。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
</entry>
<entry>
<title>生产者消费者模式</title>
<link href="http://hkeepl.github.io/posts/3680"/>
<id>http://hkeepl.github.io/posts/3680</id>
<published>2020-06-18T07:11:48.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<h1 id="生产者消费者模式"><a href="#生产者消费者模式" class="headerlink" title="生产者消费者模式"></a>生产者消费者模式</h1><p>生产者消费者模式:有一个生产者生产产品,这些产品提供给若干个消费者去消费,为了使生产者和消费者能够并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放到缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间需要保持同步。</p><span id="more"></span><p>多线程之间的同步可以使用<code>mutex</code>,<code>semaphore</code>和<code>critical_section</code>。多进程之间同步可以使用<code>mutex</code>和<code>semaphore</code>。</p><h2 id="多线程(进程)下mutex,semaphore的区别"><a href="#多线程(进程)下mutex,semaphore的区别" class="headerlink" title="多线程(进程)下mutex,semaphore的区别"></a>多线程(进程)下<code>mutex</code>,<code>semaphore</code>的区别</h2><table><thead><tr><th><code>semaphore</code></th><th>为了使一个信号从一个任务传到另一个任务。</th></tr></thead><tbody><tr><td><code>mutex</code></td><td>使受保护的共享资源在每次任务中都是按照取得与释放的顺序进行。</td></tr></tbody></table><p><code>semaphore</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/* Task 1 - Producer */</span><br><span class="line">semPost(sem_power_btn); // Send the signal</span><br><span class="line"></span><br><span class="line">/* Task 2 - Consumer */</span><br><span class="line">semPend(sem_power_btn); // Wait for signal</span><br></pre></td></tr></table></figure><p>Is the number of free identical toilet keys. Example, say we have four toilets with identical locks and keys. The semaphore count - the count of keys - is set to 4 at beginning (all four toilets are free), then the count value is decremented as people are coming in. If all toilets are full, ie. there are no free keys left, the semaphore count is 0. Now, when eq. one person leaves the toilet, semaphore is increased to 1 (one free key), and given to the next person in the queue.</p><p>信号量是一个自由的官方厕所钥匙,我们有四个厕所,他们的锁和钥匙是一样的。<br>信号量开始设置为4,表示4个厕所是自由滴,如果一个人进去了,数量就-1.<br>如果厕所满了,钥匙数目就为0,信号量数目这时也是0.如果一个人离开厕所,信号量+1,队列中的下一个人可以用啦!</p><p><code>semaphore</code>是允许多个线程进入,访问互斥资源。除了多元信号量之外,还存在一种二元信号量。即只存在是与否,0与1两种状态。</p><p><code>mutex</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">/* Task 1 */</span><br><span class="line">mutexWait(mutex_mens_room);</span><br><span class="line">// Safely use shared resource</span><br><span class="line">mutexRelease(mutex_mens_room);</span><br><span class="line"></span><br><span class="line">/* Task 2 */</span><br><span class="line">mutexWait(mutex_mens_room);</span><br><span class="line">// Safely use shared resource</span><br><span class="line">mutexRelease(mutex_mens_room);</span><br></pre></td></tr></table></figure><p>Is a key to a toilet. One person can have the key - occupy the toilet - at the time.<br>When finished, the person gives (frees) the key to the next person in the queue.</p><p><code>mutex</code>是厕所钥匙,一次只能一人那着这把钥匙去厕所。结束了,这个人把钥匙给队列中的下一个人。</p><p>它和二元信号量不同的是,占有和释放必须是同一个线程。比如互斥量M被线程A占有,那么释放的时候肯定也是A线程释放的。二元信号量则不必如此,一个二元信号量的占有和释放可以是不同线程。mutex是可以用于进程也可以用于线程的同步机制。</p><p><code>critical_section</code>:</p><p>耗费资源少,用于多线程之间的同步问题。</p><h2 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h2><h3 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h3><ol><li>一个生产者一个消费者一个缓冲区</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><thread></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> std::cout;</span><br><span class="line"><span class="keyword">using</span> std::endl;</span><br><span class="line"></span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ProducerThread</span><span class="params">(LPVOID)</span></span>;</span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ConsumerThread</span><span class="params">(LPVOID)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> kProductNum = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> g_buffer = <span class="number">0</span>;</span><br><span class="line">CRITICAL_SECTION g_criticalSection;</span><br><span class="line">HANDLE g_hEventBufEmpty;</span><br><span class="line">HANDLE g_hEventBufFull;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">::<span class="built_in">InitializeCriticalSection</span>(&g_criticalSection);</span><br><span class="line">g_hEventBufEmpty = ::<span class="built_in">CreateEvent</span>(<span class="literal">NULL</span>, FALSE, TRUE, <span class="literal">NULL</span>);</span><br><span class="line">g_hEventBufFull = ::<span class="built_in">CreateEvent</span>(<span class="literal">NULL</span>, FALSE, FALSE, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> kThreadNum = <span class="number">2</span>;</span><br><span class="line">HANDLE threadHandle[kThreadNum];</span><br><span class="line">threadHandle[<span class="number">0</span>] = <span class="built_in">CreateThread</span>(<span class="literal">NULL</span>, <span class="number">0</span>, ProducerThread, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line">threadHandle[<span class="number">1</span>] = <span class="built_in">CreateThread</span>(<span class="literal">NULL</span>, <span class="number">0</span>, ConsumerThread, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line">::<span class="built_in">WaitForMultipleObjects</span>(kThreadNum, threadHandle, TRUE, INFINITE);</span><br><span class="line"></span><br><span class="line">::<span class="built_in">DeleteCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">CloseHandle</span>(threadHandle[<span class="number">0</span>]);</span><br><span class="line">::<span class="built_in">CloseHandle</span>(threadHandle[<span class="number">1</span>]);</span><br><span class="line">::<span class="built_in">CloseHandle</span>(g_hEventBufFull);</span><br><span class="line">::<span class="built_in">CloseHandle</span>(g_hEventBufEmpty);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ProducerThread</span><span class="params">(LPVOID p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= kProductNum; ++i)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">WaitForSingleObject</span>(g_hEventBufEmpty, INFINITE);</span><br><span class="line"><span class="built_in">EnterCriticalSection</span>(&g_criticalSection);</span><br><span class="line">g_buffer = i;</span><br><span class="line">cout << <span class="string">"生产者将数据 "</span> << g_buffer << <span class="string">" 放入缓冲区!"</span> << endl;</span><br><span class="line"><span class="built_in">LeaveCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">SetEvent</span>(g_hEventBufFull);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ConsumerThread</span><span class="params">(LPVOID p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= kProductNum; ++i)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">WaitForSingleObject</span>(g_hEventBufFull, INFINITE);</span><br><span class="line"><span class="built_in">EnterCriticalSection</span>(&g_criticalSection);</span><br><span class="line">cout << <span class="string">"\t\t\t\t消费者将数据 "</span> << g_buffer << <span class="string">" 从缓冲区取出!"</span> << endl;</span><br><span class="line"><span class="built_in">LeaveCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">SetEvent</span>(g_hEventBufEmpty);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ol start="2"><li>一个生产者多个消费者多个缓冲区</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><thread></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> std::cout;</span><br><span class="line"><span class="keyword">using</span> std::endl;</span><br><span class="line"></span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ProducerThread</span><span class="params">(LPVOID)</span></span>;</span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ConsumerThread</span><span class="params">(LPVOID)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> kProductNum = <span class="number">10</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> kBufferSize = <span class="number">4</span>;</span><br><span class="line"><span class="type">int</span> g_buffer[kBufferSize] = { <span class="number">0</span> };</span><br><span class="line">CRITICAL_SECTION g_criticalSection;</span><br><span class="line">HANDLE g_hEventBufEmpty;</span><br><span class="line">HANDLE g_hEventBufFull;</span><br><span class="line"><span class="type">int</span> g_i = <span class="number">0</span>, g_j = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">::<span class="built_in">InitializeCriticalSection</span>(&g_criticalSection);</span><br><span class="line">g_hEventBufEmpty = ::<span class="built_in">CreateSemaphore</span>(<span class="literal">NULL</span>, <span class="number">4</span>, <span class="number">4</span>, <span class="literal">NULL</span>);</span><br><span class="line">g_hEventBufFull = ::<span class="built_in">CreateSemaphore</span>(<span class="literal">NULL</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> kThreadNum = <span class="number">3</span>;</span><br><span class="line">HANDLE threadHandle[kThreadNum];</span><br><span class="line">threadHandle[<span class="number">0</span>] = <span class="built_in">CreateThread</span>(<span class="literal">NULL</span>, <span class="number">0</span>, ProducerThread, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line">threadHandle[<span class="number">1</span>] = <span class="built_in">CreateThread</span>(<span class="literal">NULL</span>, <span class="number">0</span>, ConsumerThread, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line">threadHandle[<span class="number">2</span>] = <span class="built_in">CreateThread</span>(<span class="literal">NULL</span>, <span class="number">0</span>, ConsumerThread, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line">::<span class="built_in">WaitForMultipleObjects</span>(kThreadNum, threadHandle, TRUE, INFINITE);</span><br><span class="line"></span><br><span class="line">::<span class="built_in">DeleteCriticalSection</span>(&g_criticalSection);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= kThreadNum; ++i)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">CloseHandle</span>(threadHandle[i]);</span><br><span class="line">}</span><br><span class="line">::<span class="built_in">CloseHandle</span>(g_hEventBufFull);</span><br><span class="line">::<span class="built_in">CloseHandle</span>(g_hEventBufEmpty);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ProducerThread</span><span class="params">(LPVOID p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= kProductNum; ++i)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">WaitForSingleObject</span>(g_hEventBufEmpty, INFINITE);</span><br><span class="line"><span class="built_in">EnterCriticalSection</span>(&g_criticalSection);</span><br><span class="line"></span><br><span class="line">g_buffer[g_i] = i;</span><br><span class="line">cout << <span class="string">"生产者将数据 "</span> << <span class="string">"("</span> << g_i << <span class="string">" "</span> << g_buffer[g_i] << <span class="string">") 放入缓冲区!"</span> << endl;</span><br><span class="line">g_i = (g_i + <span class="number">1</span>) % kBufferSize;</span><br><span class="line"></span><br><span class="line">::<span class="built_in">LeaveCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">ReleaseSemaphore</span>(g_hEventBufFull, <span class="number">1</span>, <span class="literal">NULL</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function">DWORD WINAPI <span class="title">ConsumerThread</span><span class="params">(LPVOID p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= kProductNum; ++i)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">WaitForSingleObject</span>(g_hEventBufFull, INFINITE);</span><br><span class="line"><span class="built_in">EnterCriticalSection</span>(&g_criticalSection);</span><br><span class="line"></span><br><span class="line">cout << <span class="string">"\t\t\t\t消费者 "</span> << ::<span class="built_in">GetCurrentThreadId</span>() << <span class="string">": ("</span> << g_j << <span class="string">" "</span> << g_buffer[g_j] << <span class="string">") 从缓冲区取出!"</span> << endl;</span><br><span class="line"><span class="keyword">if</span> (g_buffer[g_j] == kProductNum)</span><br><span class="line">{</span><br><span class="line">::<span class="built_in">LeaveCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">ReleaseSemaphore</span>(g_hEventBufFull, <span class="number">1</span>, <span class="literal">NULL</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">g_j = (g_j + <span class="number">1</span>) % kBufferSize;</span><br><span class="line"></span><br><span class="line"><span class="built_in">LeaveCriticalSection</span>(&g_criticalSection);</span><br><span class="line">::<span class="built_in">ReleaseSemaphore</span>(g_hEventBufEmpty, <span class="number">1</span>, <span class="literal">NULL</span>);</span><br><span class="line">}</span><br><span class="line">cout << <span class="string">"\t\t\t\t消费者 "</span> << ::<span class="built_in">GetCurrentThreadId</span>() << <span class="string">" 退出!"</span> << endl;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="多进程"><a href="#多进程" class="headerlink" title="多进程"></a>多进程</h3><ul><li>一个常驻进程,申请共享缓冲区(共享内存),初始化信号量和互斥量</li><li>生产者进程,读取本地数据,写入共享缓冲区</li><li>消费者进程,读取共享缓冲区数据,写到本地</li></ul><p><a href="https://github.com/hkeeplearning/LearningCpp/tree/master/LongRunProcess">实现</a></p>]]></content>
<summary type="html"><h1 id="生产者消费者模式"><a href="#生产者消费者模式" class="headerlink" title="生产者消费者模式"></a>生产者消费者模式</h1><p>生产者消费者模式:有一个生产者生产产品,这些产品提供给若干个消费者去消费,为了使生产者和消费者能够并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放到缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间需要保持同步。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
<category term="设计模式" scheme="http://hkeepl.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
</entry>
<entry>
<title>C++实现多维数组</title>
<link href="http://hkeepl.github.io/posts/21835"/>
<id>http://hkeepl.github.io/posts/21835</id>
<published>2020-05-02T12:29:49.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>在Visual Studio 2010的版本上想要使用多维数组实现一个算法,但是,无奈<code>boost</code>提供的<code>multi_array</code>坑太多,在多维数组降维赋值时经常发生错误,<code>eigen</code>提供的只有二维矩阵,最新版本中有<code>tensor</code>,但在目前的产品代码库里用不了,opencv?太大。。。最后还是自己实现了一个,拿出来,抛砖引玉吧。</p><span id="more"></span><p>这里用到了<code>C++11</code>列表初始化;如果你的编译器比较旧(没错,我用的就是vs2010),可以使用C语言的<code>stdarg.h</code>进行不定参数解析,当然这里也有些小坑。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"><span class="comment">// custom_multi_array.hpp</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdexcept></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T, <span class="type">int</span> Dims></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MultiArray</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="built_in">MultiArray</span>() : <span class="built_in">mTotalDimCnt</span>(<span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">memset</span>(mDimCnt, <span class="number">0</span>, <span class="built_in">sizeof</span>(T)*Dims);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">MultiArray</span>(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &dimCnt) : <span class="built_in">mTotalDimCnt</span>(<span class="number">1</span>)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">SetMemberVariable</span>(dimCnt);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Reset</span><span class="params">(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &dimCnt)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">mTotalDimCnt = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">SetMemberVariable</span>(dimCnt);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">GetDimCnt</span><span class="params">(<span class="type">size_t</span> dimIdx)</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">if</span> (dimIdx < Dims)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> mDimCnt[dimIdx];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">GetTotalDimCnt</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> mTotalDimCnt;</span><br><span class="line">}</span><br><span class="line"><span class="function">T *<span class="title">Get</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">if</span> (mContent.<span class="built_in">empty</span>())</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> &mContent[<span class="number">0</span>];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">const</span> T *<span class="title">Get</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">if</span> (mContent.<span class="built_in">empty</span>())</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> &mContent[<span class="number">0</span>];</span><br><span class="line">}</span><br><span class="line"><span class="function">T &<span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &args)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="type">size_t</span> idx = <span class="built_in">GetIndex</span>(args);</span><br><span class="line"><span class="keyword">return</span> mContent[idx];</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception&e)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(e.<span class="built_in">what</span>());</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">const</span> T &<span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &args)</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="type">size_t</span> idx = <span class="built_in">GetIndex</span>(args);</span><br><span class="line"><span class="keyword">return</span> mContent[idx];</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception&e)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(e.<span class="built_in">what</span>());</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/// Copy constructor</span></span><br><span class="line"><span class="built_in">MultiArray</span><T, Dims>(<span class="type">const</span> MultiArray<T, Dims> &lhs)</span><br><span class="line">{</span><br><span class="line">mTotalDimCnt = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < Dims; i++)</span><br><span class="line">{</span><br><span class="line">mDimCnt[i] = lhs.mDimCnt[i];</span><br><span class="line">mTotalDimCnt *= mDimCnt[i];</span><br><span class="line">}</span><br><span class="line">mContent = lhs.mContent;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/// Assignment constructor</span></span><br><span class="line">MultiArray<T, Dims> &<span class="keyword">operator</span>=(<span class="type">const</span> MultiArray<T, Dims> &lhs)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < Dims; i++)</span><br><span class="line">{</span><br><span class="line">mDimCnt[i] = lhs.mDimCnt[i];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (lhs.mTotalDimCnt != mTotalDimCnt)</span><br><span class="line">{</span><br><span class="line">mTotalDimCnt = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < Dims; i++)</span><br><span class="line">{</span><br><span class="line">mTotalDimCnt *= mDimCnt[i];</span><br><span class="line">}</span><br><span class="line">mContent.<span class="built_in">resize</span>(mTotalDimCnt);</span><br><span class="line">}</span><br><span class="line">std::<span class="built_in">copy</span>(lhs.mContent.<span class="built_in">begin</span>(), lhs.mContent.<span class="built_in">end</span>(), mContent.<span class="built_in">begin</span>());</span><br><span class="line"><span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">SetMemberVariable</span><span class="params">(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &dimCnt)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> std::string exceptionPrefix = <span class="string">"GetIndex Exception! "</span>;</span><br><span class="line"><span class="keyword">if</span> (dimCnt.<span class="built_in">size</span>() == Dims)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < Dims; i++)</span><br><span class="line">{</span><br><span class="line">mDimCnt[i] = dimCnt[i];</span><br><span class="line">mTotalDimCnt *= mDimCnt[i];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (mTotalDimCnt > <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">mContent.<span class="built_in">resize</span>(mTotalDimCnt, <span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(exceptionPrefix + <span class="string">"Dimension count error (equal 0)!"</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(exceptionPrefix + <span class="string">"Dimension count size error!"</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">GetIndex</span><span class="params">(<span class="type">const</span> std::vector<<span class="type">size_t</span>> &args)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> std::string exceptionPrefix = <span class="string">"GetIndex Exception! "</span>;</span><br><span class="line"><span class="comment">/// Parameters check</span></span><br><span class="line"><span class="keyword">if</span> (args.<span class="built_in">size</span>() > Dims || args.<span class="built_in">empty</span>())</span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(exceptionPrefix + <span class="string">"Dimension count size error!"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">/// Assign to local variable</span></span><br><span class="line"><span class="type">size_t</span> dimCnt[Dims] = { <span class="number">0</span> };</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < args.<span class="built_in">size</span>(); i++)</span><br><span class="line">{</span><br><span class="line">dimCnt[i] = args[i];</span><br><span class="line">}</span><br><span class="line"><span class="comment">/// Get current index from args</span></span><br><span class="line"><span class="type">size_t</span> idx = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < Dims; i++)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">if</span> (dimCnt[i] >= mDimCnt[i])</span><br><span class="line">{</span><br><span class="line"><span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(exceptionPrefix + <span class="string">"Dimension count error!"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// Get current index corresponding element count</span></span><br><span class="line"><span class="type">size_t</span> t = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> j = i + <span class="number">1</span>; j < Dims; j++)</span><br><span class="line">{</span><br><span class="line">t *= mDimCnt[j];</span><br><span class="line">}</span><br><span class="line"><span class="comment">// Updata index</span></span><br><span class="line">idx += (t * dimCnt[i]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> idx;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="type">size_t</span> mDimCnt[Dims];</span><br><span class="line"><span class="type">size_t</span> mTotalDimCnt;</span><br><span class="line">std::vector<T> mContent;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>主函数,简单的测试和调用示例</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"custom_multi_array.hpp"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// main.cpp</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">{ <span class="comment">/// 构造函数</span></span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d1</span><span class="params">({ <span class="number">1</span> })</span></span>;</span><br><span class="line">std::cout << <span class="string">"Construct success"</span> << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception& e)</span><br><span class="line">{</span><br><span class="line">std::cout << e.<span class="built_in">what</span>() << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d1</span><span class="params">({ <span class="number">1</span>, <span class="number">0</span> })</span></span>;</span><br><span class="line">std::cout << <span class="string">"Construct success"</span> << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception& e)</span><br><span class="line">{</span><br><span class="line">std::cout << e.<span class="built_in">what</span>() << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d1</span><span class="params">({ <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span> })</span></span>;</span><br><span class="line">std::cout << <span class="string">"Construct success"</span> << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception& e)</span><br><span class="line">{</span><br><span class="line">std::cout << e.<span class="built_in">what</span>() << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d1</span><span class="params">({ <span class="number">1</span>, <span class="number">1</span> })</span></span>;</span><br><span class="line">std::cout << <span class="string">"Construct success"</span> << std::endl;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">catch</span> (<span class="type">const</span> std::exception& e)</span><br><span class="line">{</span><br><span class="line">std::cout << e.<span class="built_in">what</span>() << std::endl;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">{ <span class="comment">/// 复制,赋值构造函数</span></span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d1</span><span class="params">({ <span class="number">18</span>, <span class="number">2</span> })</span></span>;</span><br><span class="line">MultiArray<<span class="type">float</span>, <span class="number">2</span>> mat2d2;</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d3</span><span class="params">({ <span class="number">18</span>, <span class="number">2</span> })</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// 复制构造函数</span></span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d4</span><span class="params">(mat2d1)</span></span>;</span><br><span class="line"><span class="comment">/// 赋值构造函数</span></span><br><span class="line">mat2d2 = mat2d1; <span class="comment">// 大小不等</span></span><br><span class="line">mat2d3 = mat2d1; <span class="comment">// 大小相等</span></span><br><span class="line">}</span><br><span class="line">{ <span class="comment">/// 不同维度的赋值</span></span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 3> <span class="title">mat3d</span><span class="params">({ <span class="number">12</span>, <span class="number">18</span>, <span class="number">2</span> })</span></span>;</span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d</span><span class="params">({ <span class="number">18</span>, <span class="number">2</span> })</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">memcpy</span>(mat2d.<span class="built_in">Get</span>(), &<span class="built_in">mat3d</span>({ <span class="number">5</span> }), <span class="number">18</span> * <span class="number">2</span> * <span class="built_in">sizeof</span>(<span class="type">float</span>));</span><br><span class="line">}</span><br><span class="line">{ <span class="comment">/// 遍历输出</span></span><br><span class="line"><span class="function">MultiArray<<span class="type">float</span>, 2> <span class="title">mat2d</span><span class="params">({ <span class="number">18</span>, <span class="number">2</span> })</span></span>;</span><br><span class="line"><span class="function">std::vector<<span class="type">float</span>> <span class="title">vec</span><span class="params">(<span class="number">18</span> * <span class="number">2</span>)</span></span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < <span class="number">18</span>*<span class="number">2</span>; i++)</span><br><span class="line">{</span><br><span class="line">vec[i] = i * <span class="number">1.0f</span>;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">memcpy</span>(mat2d.<span class="built_in">Get</span>(), &vec[<span class="number">0</span>], <span class="number">18</span> * <span class="number">2</span> * <span class="built_in">sizeof</span>(<span class="type">float</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < mat2d.<span class="built_in">GetDimCnt</span>(<span class="number">0</span>); i++)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> j = <span class="number">0</span>; j < mat2d.<span class="built_in">GetDimCnt</span>(<span class="number">1</span>); j++)</span><br><span class="line">{</span><br><span class="line">std::cout << <span class="built_in">mat2d</span>({ i, j }) << <span class="string">"\t"</span>;</span><br><span class="line">}</span><br><span class="line">std::cout << <span class="string">"\n"</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>在Visual Studio 2010的版本上想要使用多维数组实现一个算法,但是,无奈<code>boost</code>提供的<code>multi_array</code>坑太多,在多维数组降维赋值时经常发生错误,<code>eigen</code>提供的只有二维矩阵,最新版本中有<code>tensor</code>,但在目前的产品代码库里用不了,opencv?太大。。。最后还是自己实现了一个,拿出来,抛砖引玉吧。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
</entry>
<entry>
<title>使用GitHub Pages搭建个人博客</title>
<link href="http://hkeepl.github.io/posts/16332"/>
<id>http://hkeepl.github.io/posts/16332</id>
<published>2020-05-02T04:55:16.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>使用GitHub搭建个人博客的过程比较简单,但是步骤比较多,写这篇博客的目的有以下几点:</p><ol><li>记录配置的过程,方便以后查找;</li><li>标记一些网上搜索到的教程中一些没有提到的地方,希望给他人提供一个参考。</li></ol><span id="more"></span><h2 id="GitHub-Pages初始化"><a href="#GitHub-Pages初始化" class="headerlink" title="GitHub Pages初始化"></a>GitHub Pages初始化</h2><h3 id="创建个人GitHub账号"><a href="#创建个人GitHub账号" class="headerlink" title="创建个人GitHub账号"></a>创建个人GitHub账号</h3><p>在GitHub上申请个人账号,如用户名:<code>zhangsan</code>。</p><h3 id="创建博客仓库"><a href="#创建博客仓库" class="headerlink" title="创建博客仓库"></a>创建博客仓库</h3><p>创建一个和账号名相同,以<code>github.io</code>结尾的仓库,如:<code>zhangsan.github.io</code>。</p><h3 id="设置该仓为GitHub-Page"><a href="#设置该仓为GitHub-Page" class="headerlink" title="设置该仓为GitHub Page"></a>设置该仓为GitHub Page</h3><p>步骤如下:</p><ul><li><p>在软件仓的主页面点击<code>Setting</code></p></li><li><p>找到<code>GitHub Pages</code>,点击<code>Choose a theme</code></p></li><li><p>然后随便选择一个主题,并对更改进行<code>commit</code></p></li></ul><p>在浏览器中输入<code>https://zhangsan.github.io</code>便可以访问网页了。</p><p>但是这样建好的网站看起来并不美观,下面我们将会使用Hexo提供的框架对网页仓进行优化</p><h2 id="优化GitHub-Pages并对仓库进行管理"><a href="#优化GitHub-Pages并对仓库进行管理" class="headerlink" title="优化GitHub Pages并对仓库进行管理"></a>优化GitHub Pages并对仓库进行管理</h2><p>参考:<a href="https://www.zhihu.com/question/21193762/answer/79109280">知乎</a>,<a href="https://hexo.io/zh-cn/docs/themes.html">hexo</a></p><h3 id="搭建的流程"><a href="#搭建的流程" class="headerlink" title="搭建的流程"></a>搭建的流程</h3><ol><li><p>给<code>zhangsan.github.io</code>仓创建一个新的分支<code>hexo</code>,这个分支主要用于存储博客源文件;</p></li><li><p>设置hexo为默认分支(因为我们只需要手动管理这个分支上的hexo网站文件)</p></li><li><p>克隆仓库到本地,并且切换到hexo分支</p></li><li><p>参考<a href="https://hexo.io/zh-cn/docs/">hexo</a>安装<code>node</code>和<code>git</code>,在hexo分支上执部署hexo</p></li><li><p>修改_config.yml中的deploy参数,即将网页文件上传到<code>master</code>上</p></li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># Deployment</span><br><span class="line">## Docs: https://hexo.io/docs/deployment.html</span><br><span class="line">deploy:</span><br><span class="line"> type: 'git'</span><br><span class="line"> repo: https://github.com/zhangsan/zhangsan.github.io.git</span><br><span class="line"> branch: master</span><br></pre></td></tr></table></figure><ol start="7"><li><p>依次执行<code>git add .</code>,<code>git commit -m "..."</code>,<code>git push origin hexo</code>提交网站相关的文件</p></li><li><p>执行<code>hexo g</code>,<code>hexo d</code>生成网站并部署到GitHub上</p></li></ol><h3 id="关于日常的改动流程"><a href="#关于日常的改动流程" class="headerlink" title="关于日常的改动流程"></a>关于日常的改动流程</h3><p>在本地对博客进行修改(添加新博文、修改样式等等)后,通过下面的流程进行管理。</p><ol><li><p>依次执行<code>git add .</code>,<code>git commit -m "..."</code>,<code>git push origin hexo</code>将改动推送到GitHub(分支应为hexo)</p></li><li><p>执行<code>hexo g</code>,<code>hexo d</code>发布网站到master分支上</p></li></ol><h3 id="本地资料丢失后的流程"><a href="#本地资料丢失后的流程" class="headerlink" title="本地资料丢失后的流程"></a>本地资料丢失后的流程</h3><p>当重装电脑之后,或者想在其他电脑上修改博客,可以使用下列步骤:</p><ol><li><p>使用<code>git clone git@github.com:zhangsan/zhangsan.github.io.git</code>拷贝仓库,并切换到<code>hexo</code>分支</p></li><li><p>在本地克隆下来的文件夹根目录下,依次执行下列指令:<code>npm install hexo</code>,<code>npm install</code>,<code>npm install hexo-deployer-git</code>。</p></li></ol><h2 id="next主题设置"><a href="#next主题设置" class="headerlink" title="next主题设置"></a>next主题设置</h2><p>参考:<a href="https://theme-next.iissnan.com/getting-started.html">next</a></p><ul><li>在仓库根目录下,输入命令:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/theme-next/hexo-theme-next.git themes/next</span><br></pre></td></tr></table></figure><ul><li>打开根目录下的<code>_config.yml</code>文件,将theme字段改为next即可</li></ul><p><strong>注意:</strong></p><ul><li><p>项目根目录下的<code>_config.yml</code>文件叫作站点配置文件</p></li><li><p>主题文件夹根目录下的<code>themes/next/_config.yml</code>文件叫作主题配置文件</p></li></ul><h3 id="给next主题添加-标签-等页面"><a href="#给next主题添加-标签-等页面" class="headerlink" title="给next主题添加[标签]等页面"></a>给next主题添加[标签]等页面</h3><p>新建页面:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ cd your-hexo-site</span><br><span class="line">$ hexo new page tags</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>设置页面类型:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">title: 标签</span><br><span class="line">date: 2014-12-22 12:39:04</span><br><span class="line">type: "tags"</span><br><span class="line">---</span><br></pre></td></tr></table></figure><p>修改菜单:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">menu:</span><br><span class="line"> home: /</span><br><span class="line"> archives: /archives</span><br><span class="line"> tags: /tags</span><br></pre></td></tr></table></figure><p><strong>特别注意:</strong>*</p><p><code>Menu</code>如果使用了图标,一定要按照下面的格式设置,小心空格</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">menu:</span><br><span class="line"> home: /|| home</span><br><span class="line"> #about: /about/|| user</span><br><span class="line"> tags: /tags/|| tags</span><br><span class="line"> categories: /categories/|| th</span><br></pre></td></tr></table></figure><h3 id="添加本地搜索插件"><a href="#添加本地搜索插件" class="headerlink" title="添加本地搜索插件"></a>添加本地搜索插件</h3><p>安装 hexo-generator-searchdb: <code>npm install hexo-generator-searchdb</code>。</p><p>在hexo的配置文件中添加如下参数:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># Local_search</span><br><span class="line">search:</span><br><span class="line"> path: search.xml</span><br><span class="line"> field: post</span><br><span class="line"> format: html</span><br><span class="line"> limit: 10000</span><br></pre></td></tr></table></figure><p>在next主题配置文件中设置如下参数:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">local_search:</span><br><span class="line"> enable: true</span><br></pre></td></tr></table></figure><h3 id="博客图片"><a href="#博客图片" class="headerlink" title="博客图片"></a>博客图片</h3><p>在博客目录中添加图片配置文件。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-renderer-marked</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">post_asset_folder: true</span><br><span class="line">marked:</span><br><span class="line"> prependRoot: true</span><br><span class="line"> postAsset: true</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>使用GitHub搭建个人博客的过程比较简单,但是步骤比较多,写这篇博客的目的有以下几点:</p>
<ol>
<li>记录配置的过程,方便以后查找;</li>
<li>标记一些网上搜索到的教程中一些没有提到的地方,希望给他人提供一个参考。</li>
</ol></summary>
<category term="博客" scheme="http://hkeepl.github.io/tags/%E5%8D%9A%E5%AE%A2/"/>
</entry>
<entry>
<title>C++编码总结</title>
<link href="http://hkeepl.github.io/posts/9877"/>
<id>http://hkeepl.github.io/posts/9877</id>
<published>2020-03-06T07:11:48.000Z</published>
<updated>2022-08-27T08:46:26.347Z</updated>
<content type="html"><![CDATA[<p>总结日常开发中的一些小知识。</p><span id="more"></span><h2 id="restrict用法"><a href="#restrict用法" class="headerlink" title="restrict用法"></a><code>restrict</code>用法</h2><p>只能用于修饰指针,表示同一块内存不能被别的指针引用。有利于编译器进行优化。</p><p>示例:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">foo</span><span class="params">(<span class="type">int</span> *a, <span class="type">int</span> *b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> *a = <span class="number">5</span>;</span><br><span class="line"> *b = <span class="number">6</span>;</span><br><span class="line"> <span class="keyword">return</span> *a + *b;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">rfoo</span><span class="params">(<span class="type">int</span> * __restrict a, <span class="type">int</span> * __restrict b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> *a = <span class="number">5</span>;</span><br><span class="line"> *b = <span class="number">6</span>;</span><br><span class="line"> <span class="keyword">return</span> *a + *b;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>编译出的汇编代码:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">foo:</span><br><span class="line">.seh_endprologue</span><br><span class="line">movl$5, (%rcx)</span><br><span class="line">movl$6, (%rdx)</span><br><span class="line">movl(%rcx), %eax</span><br><span class="line">addl$6, %eax</span><br><span class="line">ret</span><br><span class="line">.seh_endproc</span><br><span class="line">.p2align 4,,15</span><br><span class="line">.globlrfoo</span><br><span class="line">.defrfoo;.scl2;.type32;.endef</span><br><span class="line">.seh_procrfoo</span><br><span class="line">rfoo:</span><br><span class="line">.seh_endprologue</span><br><span class="line">movl$11, %eax</span><br><span class="line">movl$5, (%rcx)</span><br><span class="line">movl$6, (%rdx)</span><br><span class="line">ret</span><br></pre></td></tr></table></figure><h2 id="const用法"><a href="#const用法" class="headerlink" title="const用法"></a><code>const</code>用法</h2><p>如果确定一个变量是只读的,在作用域内不会改变它的值,就将其声明为<code>const</code>。注意<code>const</code>是只读的意思,而不能狭隘的认为是常量。</p><h2 id="extern-quot-C-quot-用法"><a href="#extern-quot-C-quot-用法" class="headerlink" title="extern "C"用法"></a><code>extern "C"</code>用法</h2><ol><li><p>不要在<code>extern "C"</code>的作用范围内中使用<code>namespace</code></p></li><li><p>不要在<code>extern "C"</code>范围内声明的函数签名中使用C++的特性</p></li></ol><p>不规范的写法:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Img {</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">Function1</span><span class="params">(<span class="type">float</span> f1, <span class="type">float</span> &f2)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">Function2</span><span class="params">(std::vector<<span class="type">float</span>> &v, <span class="type">float</span> *f2)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">Function3</span><span class="params">(<span class="type">int</span> lhs)</span></span>;</span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">Function3</span><span class="params">(<span class="type">float</span> lhs)</span></span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyStruct</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">float</span> *f;</span><br><span class="line"> <span class="type">int</span> len;</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">Function4</span><span class="params">(MyStruct * myStr)</span></span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyCls</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">MyCls</span>();</span><br><span class="line"> ~<span class="built_in">MyCls</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h2 id="宏定义"><a href="#宏定义" class="headerlink" title="宏定义"></a>宏定义</h2><p>尽管我们常说要禁用宏定义,但是它还是有一些优点的。比如常用的:</p><ol><li>使用宏定义进行一些调试代码的条件编译</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> _USER_DEBUG</span></span><br><span class="line"><span class="function">std::ofstream <span class="title">ofs</span><span class="params">(<span class="string">"out.raw"</span>, std::ios::binary)</span></span>;</span><br><span class="line"><span class="keyword">if</span> (ofs.<span class="built_in">is_open</span>())</span><br><span class="line">{</span><br><span class="line"> ofs.<span class="built_in">write</span>(data, size);</span><br><span class="line"> ofs.<span class="built_in">close</span>();</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// _USER_DEBUG</span></span></span><br></pre></td></tr></table></figure><ol start="2"><li>函数调用的错误信息整理</li></ol><p>比如,在我们的产品代码中,在错误发生时通常需要输出错误的日志信息。之前的错误日志打印函数是这样的:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">IRTFunctor::LogNotifyError</span><span class="params">(<span class="type">const</span> std::string &errorInfo, <span class="type">bool</span> isLogInFunction)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">if</span> (!m_bErrorHappenedFlag)</span><br><span class="line">{</span><br><span class="line">m_bErrorHappenedFlag = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (isLogInFunction)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">LOG2_ERROR</span>(m_logger, errorInfo);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">uint64_t</span> svcUid = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> (!Img::SvcUidParser::<span class="built_in">FindSvcUid</span>(errorInfo, svcUid))</span><br><span class="line">{</span><br><span class="line">svcUid = uidUnknown_Err1;</span><br><span class="line"><span class="built_in">const_cast</span><std::string &>(errorInfo) = Img::SvcUidParser::<span class="built_in">SetSvcUid</span>(errorInfo, svcUid);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">auto</span> strSvcUid = Img::SvcUidParser::<span class="built_in">GetSvcCode</span>(svcUid);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (isLogInFunction)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">LOG2_ERROR_SVC</span>(m_logger, svcUid, errorInfo);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">NotifyJobDetailInfo</span>(strSvcUid);</span><br><span class="line"><span class="built_in">NotifyError</span>(errorInfo);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Sleep</span>(SleepTime);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样打印的一个问题是LOG中只有<code>IRTFunctor::LogNotifyError</code>函数的函数名和打印日志行,不能快速的找到错误发生的地方,改进后:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> ILOG_NOTIFY_ERR</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> ILOG_NOTIFY_ERR</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ILOG_NOTIFY_ERR(LoggerPtr, SvcUid, ErrStrStream) \</span></span><br><span class="line"><span class="meta">do { \</span></span><br><span class="line"><span class="meta">LOG2_ERROR(LoggerPtr, ErrStrStream); \</span></span><br><span class="line"><span class="meta">std::stringstream ss; ss << ErrStrStream; \</span></span><br><span class="line"><span class="meta">auto errorInfo = Img::SvcUidParser::SetSvcUid(ss.str(), SvcUid); \</span></span><br><span class="line"><span class="meta">LOG2_ERROR_SVC(LoggerPtr, SvcUid, errorInfo); \</span></span><br><span class="line"><span class="meta">LogNotifyError(errorInfo, false); \</span></span><br><span class="line"><span class="meta">} while(false)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> ILOG_NOTIFY_ERR_NO_SUID</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> ILOG_NOTIFY_ERR_NO_SUID</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ILOG_NOTIFY_ERR_NO_SUID(LoggerPtr, ErrStrStream) \</span></span><br><span class="line"><span class="meta">ILOG_NOTIFY_ERR(LoggerPtr, uidUnknown_Err, ErrStrStream)</span></span><br></pre></td></tr></table></figure><ol start="3"><li>函数定义时抛出异常</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> IMG_THROW_ERROR(ErrStr, ExceptionType) \</span></span><br><span class="line"><span class="meta">do {\</span></span><br><span class="line"><span class="meta">std::stringstream ss; ss << ErrStr << <span class="string">" ErrLineNumber:"</span> << __LINE__; \</span></span><br><span class="line"><span class="meta">throw ExceptionType(ss.str()); \</span></span><br><span class="line"><span class="meta">} while(false)</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>总结日常开发中的一些小知识。</p></summary>
<category term="C++" scheme="http://hkeepl.github.io/tags/C/"/>
</entry>
</feed>