@@ -421,7 +421,7 @@ <h2 id="index-_1">前言</h2>
421
421
<blockquote>
422
422
<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>
423
423
</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>
425
425
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
426
426
<h2 id="index-_2">格式约定</h2>
427
427
<blockquote>
@@ -1505,6 +1505,7 @@ <h2 id="symbols-linkage">符号的链接类型 (linkage)</h2>
1505
1505
<li><a href="#cpp_tricks-_8">提前返回</a></li>
1506
1506
<li><a href="#cpp_tricks-lambda">立即调用的 Lambda</a></li>
1507
1507
<li><a href="#cpp_tricks-lambda_1">Lambda 复用代码</a></li>
1508
+ <li><a href="#cpp_tricks-if-else">打表法代替 if-else</a></li>
1508
1509
<li><a href="#cpp_tricks-inline">类内静态成员 inline</a></li>
1509
1510
<li><a href="#cpp_tricks-make_pair">别再 make_pair 啦!</a></li>
1510
1511
<li><a href="#cpp_tricks-insert">insert 不会替换现有值哦</a></li>
@@ -1870,6 +1871,32 @@ <h2 id="cpp_tricks-lambda">立即调用的 Lambda</h2>
1870
1871
return false;
1871
1872
}
1872
1873
</code></pre>
1874
+ <p>但有时,我们的函数可能写了额外的操作,做完查找后不想直接返回。用 <code>return</code> 提前返回的话,下面 <code>do_final</code> 部分就无法执行到,只能复读一遍。</p>
1875
+ <pre><code class="language-cpp">void find(const vector<int> &v, int target) {
1876
+ for (int i = 0; i < 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<int> &v, int target) {
1889
+ for (int i = 0; i < 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>
1873
1900
<p>可以包裹一个立即调用的 Lambda 块 <code>[&] { ... } ()</code>,限制提前返回的范围:</p>
1874
1901
<pre><code class="language-cpp">void find(const vector<int> &v, int target) {
1875
1902
bool found = [&] {
@@ -1885,41 +1912,102 @@ <h2 id="cpp_tricks-lambda">立即调用的 Lambda</h2>
1885
1912
}
1886
1913
}
1887
1914
</code></pre>
1915
+ <p>这样,return 最多只能打断到当前 Lambda 函数结束的位置,而不能打断整个大函数了。</p>
1888
1916
<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 < cat_arr.size(); i++) {
1921
+ res += cat_arr[i].age;
1922
+ count += cat_arr[i].count;
1923
+ }
1924
+ for (int i = 0; i < dog_arr.size(); i++) {
1925
+ res += dog_arr[i].age;
1926
+ count += dog_arr[i].count;
1927
+ }
1928
+ for (int i = 0; i < 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 <class T>
1937
+ void cihou(int &res, int &count, std::vector<T> const &arr) {
1938
+ for (int i = 0; i < 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>[&]</code> 语法,自动捕获所有用到的局部变量为引用!无需一个个传递局部变量引用作为函数参数,没有复读,更加无感。只有重复代码中真正区别的部分需要传参数。</p>
1958
+ <pre><code class="language-cpp">void calc_average() {
1959
+ int res = 0;
1960
+ int count = 0;
1961
+ auto cihou = [&] { // 局部 Lambda 的好处:自动帮你捕获 res 和 count!
1962
+ for (int i = 0; i < 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>
1889
1976
<pre><code class="language-cpp">vector<string> spilt(string str) {
1890
1977
vector<string> list;
1891
1978
string last;
1892
1979
for (char c: str) {
1893
1980
if (c == ' ') {
1894
1981
list.push_back(last);
1895
- last.clear() ;
1982
+ last = "" ;
1896
1983
} else {
1897
- last.push_back(c) ;
1984
+ last += c ;
1898
1985
}
1899
1986
}
1900
1987
list.push_back(last);
1901
1988
return list;
1902
1989
}
1903
1990
</code></pre>
1904
- <p>上面的代码可以用 Lambda 复用:</p>
1991
+ <p>上面的代码中重复的部分 <code>list.push_back(last);</code> 可以用 Lambda 复用,把重复的操作封装成局部的 Lambda :</p>
1905
1992
<pre><code class="language-cpp">vector<string> spilt(string str) {
1906
1993
vector<string> list;
1907
1994
string last;
1908
- auto push = [&] {
1995
+ auto push_last = [&] {
1909
1996
list.push_back(last);
1910
- last.clear() ;
1997
+ last = "" ;
1911
1998
};
1912
1999
for (char c: str) {
1913
2000
if (c == ' ') {
1914
- push ();
2001
+ push_last ();
1915
2002
} else {
1916
- last.push_back(c) ;
2003
+ last += c ;
1917
2004
}
1918
2005
}
1919
- push ();
2006
+ push_last ();
1920
2007
return list;
1921
2008
}
1922
2009
</code></pre>
2010
+ <h2 id="cpp_tricks-if-else">打表法代替 if-else</h2>
1923
2011
<h2 id="cpp_tricks-inline">类内静态成员 inline</h2>
1924
2012
<p>在头文件中定义结构体的 static 成员时:</p>
1925
2013
<pre><code class="language-cpp">struct Class {
0 commit comments