Skip to content

Commit 516f3b6

Browse files
committed
deploy: 61f4d39
1 parent 0af184d commit 516f3b6

File tree

4 files changed

+199
-19
lines changed

4 files changed

+199
-19
lines changed

cpp_tricks/index.html

+100-8
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@
284284
<ul class="nav flex-column">
285285
</ul>
286286
</li>
287+
<li class="nav-item" data-bs-level="2"><a href="#if-else" class="nav-link">打表法代替 if-else</a>
288+
<ul class="nav flex-column">
289+
</ul>
290+
</li>
287291
<li class="nav-item" data-bs-level="2"><a href="#inline" class="nav-link">类内静态成员 inline</a>
288292
<ul class="nav flex-column">
289293
</ul>
@@ -493,6 +497,7 @@ <h1 id="c">应知应会 C++ 小技巧</h1>
493497
<li><a href="#_8">提前返回</a></li>
494498
<li><a href="#lambda">立即调用的 Lambda</a></li>
495499
<li><a href="#lambda_1">Lambda 复用代码</a></li>
500+
<li><a href="#if-else">打表法代替 if-else</a></li>
496501
<li><a href="#inline">类内静态成员 inline</a></li>
497502
<li><a href="#make_pair">别再 make_pair 啦!</a></li>
498503
<li><a href="#insert">insert 不会替换现有值哦</a></li>
@@ -858,6 +863,32 @@ <h2 id="lambda">立即调用的 Lambda</h2>
858863
return false;
859864
}
860865
</code></pre>
866+
<p>但有时,我们的函数可能写了额外的操作,做完查找后不想直接返回。用 <code>return</code> 提前返回的话,下面 <code>do_final</code> 部分就无法执行到,只能复读一遍。</p>
867+
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
868+
for (int i = 0; i &lt; v.size(); ++i) {
869+
if (v[i] == target) {
870+
do_something();
871+
do_final();
872+
return;
873+
}
874+
}
875+
do_other();
876+
do_final();
877+
}
878+
</code></pre>
879+
<p>改用 <code>goto</code> 来打断循环,又不美观了。</p>
880+
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
881+
for (int i = 0; i &lt; v.size(); ++i) {
882+
if (v[i] == target) {
883+
do_something();
884+
goto final;
885+
}
886+
}
887+
do_other();
888+
final:
889+
do_final();
890+
}
891+
</code></pre>
861892
<p>可以包裹一个立即调用的 Lambda 块 <code>[&amp;] { ... } ()</code>,限制提前返回的范围:</p>
862893
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
863894
bool found = [&amp;] {
@@ -873,41 +904,102 @@ <h2 id="lambda">立即调用的 Lambda</h2>
873904
}
874905
}
875906
</code></pre>
907+
<p>这样,return 最多只能打断到当前 Lambda 函数结束的位置,而不能打断整个大函数了。</p>
876908
<h2 id="lambda_1">Lambda 复用代码</h2>
909+
<pre><code class="language-cpp">void calc_average() {
910+
int res = 0;
911+
int count = 0;
912+
for (int i = 0; i &lt; cat_arr.size(); i++) {
913+
res += cat_arr[i].age;
914+
count += cat_arr[i].count;
915+
}
916+
for (int i = 0; i &lt; dog_arr.size(); i++) {
917+
res += dog_arr[i].age;
918+
count += dog_arr[i].count;
919+
}
920+
for (int i = 0; i &lt; pig_arr.size(); i++) {
921+
res += pig_arr[i].age;
922+
count += pig_arr[i].count;
923+
}
924+
}
925+
</code></pre>
926+
<p>你是否被迫写出以上这种复读代码?大部分内容都是重复的,每次只有一小部分修改,导致不得不复读很多遍,非常恼人!</p>
927+
<p>“设计模式”官腔的做法是额外定义一个函数,把重复的部分代码功能抽出来变成一个 <code>cihou</code> 模板函数,然后再 <code>calc_average</code> 里只需要调用三次这个 <code>cihou</code> 函数即可实现复用:</p>
928+
<pre><code class="language-cpp">template &lt;class T&gt;
929+
void cihou(int &amp;res, int &amp;count, std::vector&lt;T&gt; const &amp;arr) {
930+
for (int i = 0; i &lt; arr.size(); i++) {
931+
res += arr[i].age;
932+
count += arr[i].count;
933+
}
934+
}
935+
936+
void calc_average() {
937+
int res = 0;
938+
int count = 0;
939+
cihou(res, count, cat_arr);
940+
cihou(res, count, dog_arr);
941+
cihou(res, count, pig_arr);
942+
}
943+
</code></pre>
944+
<p>然而,额外定义一个函数也太大费周章了,而且还需要把所有用到的局部变量作为参数传进去!参数部分依然需要反复复读,并且还需要一个个指定所有参数的类型,写一长串模板等。最重要的是定义外部函数会污染了全局名字空间。</p>
945+
<blockquote>
946+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 洁癖程序员:脏了我的眼!</p>
947+
</blockquote>
948+
<p>使用 Lambda,就可以让你在 <code>calc_average</code> 当前函数里“就地解决”,无需定义外部函数。</p>
949+
<p>更妙的是:Lambda 支持 <code>[&amp;]</code> 语法,自动捕获所有用到的局部变量为引用!无需一个个传递局部变量引用作为函数参数,没有复读,更加无感。只有重复代码中真正区别的部分需要传参数。</p>
950+
<pre><code class="language-cpp">void calc_average() {
951+
int res = 0;
952+
int count = 0;
953+
auto cihou = [&amp;] { // 局部 Lambda 的好处:自动帮你捕获 res 和 count!
954+
for (int i = 0; i &lt; arr.size(); i++) {
955+
res += arr[i].age;
956+
count += arr[i].count;
957+
}
958+
};
959+
cihou(cat_arr);
960+
cihou(dog_arr);
961+
cihou(pig_arr);
962+
}
963+
</code></pre>
964+
<blockquote>
965+
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 现在只有两个变量 <code>res</code><code>count</code> 可能还没什么,如果重复的部分用到一大堆变量,同时还有时候用到,有时候用不到的话,你就觉得 Lambda 好用了。</p>
966+
</blockquote>
967+
<p>例如字符串切片函数典型的一种实现中,因为“尾巴”的伺候和“主体”的伺候,就会产生重复代码:</p>
877968
<pre><code class="language-cpp">vector&lt;string&gt; spilt(string str) {
878969
vector&lt;string&gt; list;
879970
string last;
880971
for (char c: str) {
881972
if (c == ' ') {
882973
list.push_back(last);
883-
last.clear();
974+
last = &quot;&quot;;
884975
} else {
885-
last.push_back(c);
976+
last += c;
886977
}
887978
}
888979
list.push_back(last);
889980
return list;
890981
}
891982
</code></pre>
892-
<p>上面的代码可以用 Lambda 复用:</p>
983+
<p>上面的代码中重复的部分 <code>list.push_back(last);</code> 可以用 Lambda 复用,把重复的操作封装成局部的 Lambda</p>
893984
<pre><code class="language-cpp">vector&lt;string&gt; spilt(string str) {
894985
vector&lt;string&gt; list;
895986
string last;
896-
auto push = [&amp;] {
987+
auto push_last = [&amp;] {
897988
list.push_back(last);
898-
last.clear();
989+
last = &quot;&quot;;
899990
};
900991
for (char c: str) {
901992
if (c == ' ') {
902-
push();
993+
push_last();
903994
} else {
904-
last.push_back(c);
995+
last += c;
905996
}
906997
}
907-
push();
998+
push_last();
908999
return list;
9091000
}
9101001
</code></pre>
1002+
<h2 id="if-else">打表法代替 if-else</h2>
9111003
<h2 id="inline">类内静态成员 inline</h2>
9121004
<p>在头文件中定义结构体的 static 成员时:</p>
9131005
<pre><code class="language-cpp">struct Class {

index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ <h2 id="_1">前言</h2>
292292
<blockquote>
293293
<p><img src="./img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
294294
</blockquote>
295-
<p>更新时间:2025年01月02日 15:20:32 (UTC+08:00)</p>
295+
<p>更新时间:2025年01月02日 15:39:09 (UTC+08:00)</p>
296296
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
297297
<h2 id="_2">格式约定</h2>
298298
<blockquote>

print_page/index.html

+97-9
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ <h2 id="index-_1">前言</h2>
421421
<blockquote>
422422
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
423423
</blockquote>
424-
<p>更新时间:2025年01月02日 15:20:32 (UTC+08:00)</p>
424+
<p>更新时间:2025年01月02日 15:39:09 (UTC+08:00)</p>
425425
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
426426
<h2 id="index-_2">格式约定</h2>
427427
<blockquote>
@@ -1505,6 +1505,7 @@ <h2 id="symbols-linkage">符号的链接类型 (linkage)</h2>
15051505
<li><a href="#cpp_tricks-_8">提前返回</a></li>
15061506
<li><a href="#cpp_tricks-lambda">立即调用的 Lambda</a></li>
15071507
<li><a href="#cpp_tricks-lambda_1">Lambda 复用代码</a></li>
1508+
<li><a href="#cpp_tricks-if-else">打表法代替 if-else</a></li>
15081509
<li><a href="#cpp_tricks-inline">类内静态成员 inline</a></li>
15091510
<li><a href="#cpp_tricks-make_pair">别再 make_pair 啦!</a></li>
15101511
<li><a href="#cpp_tricks-insert">insert 不会替换现有值哦</a></li>
@@ -1870,6 +1871,32 @@ <h2 id="cpp_tricks-lambda">立即调用的 Lambda</h2>
18701871
return false;
18711872
}
18721873
</code></pre>
1874+
<p>但有时,我们的函数可能写了额外的操作,做完查找后不想直接返回。用 <code>return</code> 提前返回的话,下面 <code>do_final</code> 部分就无法执行到,只能复读一遍。</p>
1875+
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
1876+
for (int i = 0; i &lt; v.size(); ++i) {
1877+
if (v[i] == target) {
1878+
do_something();
1879+
do_final();
1880+
return;
1881+
}
1882+
}
1883+
do_other();
1884+
do_final();
1885+
}
1886+
</code></pre>
1887+
<p>改用 <code>goto</code> 来打断循环,又不美观了。</p>
1888+
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
1889+
for (int i = 0; i &lt; v.size(); ++i) {
1890+
if (v[i] == target) {
1891+
do_something();
1892+
goto final;
1893+
}
1894+
}
1895+
do_other();
1896+
final:
1897+
do_final();
1898+
}
1899+
</code></pre>
18731900
<p>可以包裹一个立即调用的 Lambda 块 <code>[&amp;] { ... } ()</code>,限制提前返回的范围:</p>
18741901
<pre><code class="language-cpp">void find(const vector&lt;int&gt; &amp;v, int target) {
18751902
bool found = [&amp;] {
@@ -1885,41 +1912,102 @@ <h2 id="cpp_tricks-lambda">立即调用的 Lambda</h2>
18851912
}
18861913
}
18871914
</code></pre>
1915+
<p>这样,return 最多只能打断到当前 Lambda 函数结束的位置,而不能打断整个大函数了。</p>
18881916
<h2 id="cpp_tricks-lambda_1">Lambda 复用代码</h2>
1917+
<pre><code class="language-cpp">void calc_average() {
1918+
int res = 0;
1919+
int count = 0;
1920+
for (int i = 0; i &lt; cat_arr.size(); i++) {
1921+
res += cat_arr[i].age;
1922+
count += cat_arr[i].count;
1923+
}
1924+
for (int i = 0; i &lt; dog_arr.size(); i++) {
1925+
res += dog_arr[i].age;
1926+
count += dog_arr[i].count;
1927+
}
1928+
for (int i = 0; i &lt; pig_arr.size(); i++) {
1929+
res += pig_arr[i].age;
1930+
count += pig_arr[i].count;
1931+
}
1932+
}
1933+
</code></pre>
1934+
<p>你是否被迫写出以上这种复读代码?大部分内容都是重复的,每次只有一小部分修改,导致不得不复读很多遍,非常恼人!</p>
1935+
<p>“设计模式”官腔的做法是额外定义一个函数,把重复的部分代码功能抽出来变成一个 <code>cihou</code> 模板函数,然后再 <code>calc_average</code> 里只需要调用三次这个 <code>cihou</code> 函数即可实现复用:</p>
1936+
<pre><code class="language-cpp">template &lt;class T&gt;
1937+
void cihou(int &amp;res, int &amp;count, std::vector&lt;T&gt; const &amp;arr) {
1938+
for (int i = 0; i &lt; arr.size(); i++) {
1939+
res += arr[i].age;
1940+
count += arr[i].count;
1941+
}
1942+
}
1943+
1944+
void calc_average() {
1945+
int res = 0;
1946+
int count = 0;
1947+
cihou(res, count, cat_arr);
1948+
cihou(res, count, dog_arr);
1949+
cihou(res, count, pig_arr);
1950+
}
1951+
</code></pre>
1952+
<p>然而,额外定义一个函数也太大费周章了,而且还需要把所有用到的局部变量作为参数传进去!参数部分依然需要反复复读,并且还需要一个个指定所有参数的类型,写一长串模板等。最重要的是定义外部函数会污染了全局名字空间。</p>
1953+
<blockquote>
1954+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 洁癖程序员:脏了我的眼!</p>
1955+
</blockquote>
1956+
<p>使用 Lambda,就可以让你在 <code>calc_average</code> 当前函数里“就地解决”,无需定义外部函数。</p>
1957+
<p>更妙的是:Lambda 支持 <code>[&amp;]</code> 语法,自动捕获所有用到的局部变量为引用!无需一个个传递局部变量引用作为函数参数,没有复读,更加无感。只有重复代码中真正区别的部分需要传参数。</p>
1958+
<pre><code class="language-cpp">void calc_average() {
1959+
int res = 0;
1960+
int count = 0;
1961+
auto cihou = [&amp;] { // 局部 Lambda 的好处:自动帮你捕获 res 和 count!
1962+
for (int i = 0; i &lt; arr.size(); i++) {
1963+
res += arr[i].age;
1964+
count += arr[i].count;
1965+
}
1966+
};
1967+
cihou(cat_arr);
1968+
cihou(dog_arr);
1969+
cihou(pig_arr);
1970+
}
1971+
</code></pre>
1972+
<blockquote>
1973+
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 现在只有两个变量 <code>res</code> 和 <code>count</code> 可能还没什么,如果重复的部分用到一大堆变量,同时还有时候用到,有时候用不到的话,你就觉得 Lambda 好用了。</p>
1974+
</blockquote>
1975+
<p>例如字符串切片函数典型的一种实现中,因为“尾巴”的伺候和“主体”的伺候,就会产生重复代码:</p>
18891976
<pre><code class="language-cpp">vector&lt;string&gt; spilt(string str) {
18901977
vector&lt;string&gt; list;
18911978
string last;
18921979
for (char c: str) {
18931980
if (c == ' ') {
18941981
list.push_back(last);
1895-
last.clear();
1982+
last = &quot;&quot;;
18961983
} else {
1897-
last.push_back(c);
1984+
last += c;
18981985
}
18991986
}
19001987
list.push_back(last);
19011988
return list;
19021989
}
19031990
</code></pre>
1904-
<p>上面的代码可以用 Lambda 复用:</p>
1991+
<p>上面的代码中重复的部分 <code>list.push_back(last);</code> 可以用 Lambda 复用,把重复的操作封装成局部的 Lambda:</p>
19051992
<pre><code class="language-cpp">vector&lt;string&gt; spilt(string str) {
19061993
vector&lt;string&gt; list;
19071994
string last;
1908-
auto push = [&amp;] {
1995+
auto push_last = [&amp;] {
19091996
list.push_back(last);
1910-
last.clear();
1997+
last = &quot;&quot;;
19111998
};
19121999
for (char c: str) {
19132000
if (c == ' ') {
1914-
push();
2001+
push_last();
19152002
} else {
1916-
last.push_back(c);
2003+
last += c;
19172004
}
19182005
}
1919-
push();
2006+
push_last();
19202007
return list;
19212008
}
19222009
</code></pre>
2010+
<h2 id="cpp_tricks-if-else">打表法代替 if-else</h2>
19232011
<h2 id="cpp_tricks-inline">类内静态成员 inline</h2>
19242012
<p>在头文件中定义结构体的 static 成员时:</p>
19252013
<pre><code class="language-cpp">struct Class {

search/search_index.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)