Skip to content

Commit a5d7d17

Browse files
committed
deploy: 270dbef
1 parent 94e35df commit a5d7d17

File tree

11 files changed

+203
-259
lines changed

11 files changed

+203
-259
lines changed

404.html

-4
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href="/." class="dropdown-item">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="/start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="/helloworld/" class="dropdown-item">你好,世界</a>
5955
</li>

functional/index.html

-4
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href=".." class="dropdown-item">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="../start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="../helloworld/" class="dropdown-item">你好,世界</a>
5955
</li>

functions/index.html

-4
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href=".." class="dropdown-item">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="../start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="../helloworld/" class="dropdown-item">你好,世界</a>
5955
</li>

helloworld/index.html

+1-5
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href=".." class="dropdown-item">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="../start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="./" class="dropdown-item active" aria-current="page">你好,世界</a>
5955
</li>
@@ -94,7 +90,7 @@
9490
</a>
9591
</li>
9692
<li class="nav-item">
97-
<a rel="prev" href="../start/" class="nav-link">
93+
<a rel="prev" href=".." class="nav-link">
9894
<i class="fa fa-arrow-left"></i> Previous
9995
</a>
10096
</li>

index.html

+169-8
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href="." class="dropdown-item active" aria-current="page">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="helloworld/" class="dropdown-item">你好,世界</a>
5955
</li>
@@ -99,7 +95,7 @@
9995
</a>
10096
</li>
10197
<li class="nav-item">
102-
<a rel="next" href="start/" class="nav-link">
98+
<a rel="next" href="helloworld/" class="nav-link">
10399
Next <i class="fa fa-arrow-right"></i>
104100
</a>
105101
</li>
@@ -125,20 +121,185 @@
125121
<ul class="nav flex-column">
126122
</ul>
127123
</li>
124+
125+
<li class="nav-item" data-bs-level="1"><a href="#_1" class="nav-link">前言</a>
126+
<ul class="nav flex-column">
127+
<li class="nav-item" data-bs-level="2"><a href="#_2" class="nav-link">格式约定</a>
128+
<ul class="nav flex-column">
129+
</ul>
130+
</li>
131+
<li class="nav-item" data-bs-level="2"><a href="#_3" class="nav-link">观前须知</a>
132+
<ul class="nav flex-column">
133+
</ul>
134+
</li>
135+
<li class="nav-item" data-bs-level="2"><a href="#_4" class="nav-link">举个例子</a>
136+
<ul class="nav flex-column">
137+
</ul>
138+
</li>
139+
</ul>
140+
</li>
128141
</ul>
129142
</div>
130143
</div></div>
131144
<div class="col-md-9" role="main">
132145

133146
<h1 id="c">小彭老师现代 C++ 大典</h1>
134147
<p>小彭大典是一本关于现代 C++ 编程的权威指南,它涵盖了从基础知识到高级技巧的内容,适合初学者和有经验的程序员阅读。本书由小彭老师亲自编写,通过简单易懂的语言和丰富的示例,帮助读者快速掌握 C++ 的核心概念,并学会如何运用它们来解决实际问题。</p>
135-
<p><a href="start/">点击此处开始阅读第一章</a></p>
136-
<p>你也可以在本页面上方导航栏的“章节列表”中,选择感兴趣的章节阅读。</p>
148+
<blockquote>
149+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 敢承诺:土木老哥也能看懂!</p>
150+
</blockquote>
151+
<h1 id="_1">前言</h1>
152+
<p>推荐用手机或平板<strong>竖屏</strong>观看,可以在床或沙发上躺着。</p>
153+
<p>用电脑看的话,可以按 <code>WIN + ←</code>,把本书的浏览器窗口放在屏幕左侧,右侧是你的 IDE。一边看一边自己动手做实验。</p>
154+
<p><img alt="" src="img/slide.jpg" /></p>
155+
<blockquote>
156+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 请坐和放宽。</p>
157+
</blockquote>
158+
<p>可以按顺序阅读,也可以在本页面上方导航栏的“章节列表”中,选择感兴趣的章节阅读。</p>
137159
<p>本书完全开源和免费,GitHub 仓库:https://github.com/parallel101/cppguidebook</p>
138160
<blockquote>
139161
<p>如果你是在付费群中“买”到本书,或者打着小彭老师名号卖课,说明你可能是私有制的受害者。因为小彭老师从来没有付费才能看的课程,所有小彭老师课程都对全球互联网开放。</p>
140162
</blockquote>
141-
<p>如果你在阅读过程中遇到任何问题,可以在 <a href="https://github.com/parallel101/cppguidebook/issues">GitHub Issues</a> 中提出,小彭老师会尽力解答。</p></div>
163+
<p>如果你在阅读过程中遇到任何问题,可以在 <a href="https://github.com/parallel101/cppguidebook/issues">GitHub Issues</a> 中提出,小彭老师会尽力解答。</p>
164+
<h2 id="_2">格式约定</h2>
165+
<blockquote>
166+
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 用这种颜色字体书写的内容是温馨提示</p>
167+
<p><img src="../img/warning.png" height="30px" width="auto" style="margin: 0; border: none"/> 用这种颜色字体书写的内容是可能犯错的警告</p>
168+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 用这种颜色字体书写的内容是笑话或趣味寓言故事</p>
169+
<p><img src="../img/book.png" height="30px" width="auto" style="margin: 0; border: none"/> 用这种颜色书写的是补充说明的课外阅读,看不懂也没关系</p>
170+
<p><img src="../img/question.png" height="30px" width="auto" style="margin: 0; border: none"/> 用这种颜色字体书写的是初学者可暂时不用理解的细节</p>
171+
</blockquote>
172+
<ul>
173+
<li>术语名称: 这里是术语的定义。</li>
174+
</ul>
175+
<h2 id="_3">观前须知</h2>
176+
<p>与大多数现有教材不同的是,本课程将会采用“倒叙”的形式,从最新的 <strong>C++23</strong> 讲起!然后讲 C++20、C++17、C++14、C++11,慢慢讲到最原始的 C++98。</p>
177+
<p>不用担心,越是现代的 C++,学起来反而更容易!反而古代 C++ 才<strong>又臭又长</strong></p>
178+
<p>很多同学想当然地误以为 C++98 最简单,哼哧哼哧费老大劲从 C++98 开始学,才是错误的。</p>
179+
<p>为了应付缺胳膊少腿的 C++98,人们发明了各种<strong>繁琐无谓</strong>的写法,在现代 C++ 中,早就已经被更<strong>简洁直观</strong>的写法替代了。</p>
180+
<blockquote>
181+
<p><img src="../img/book.png" height="30px" width="auto" style="margin: 0; border: none"/> 例如所谓的 safe-bool idiom,写起来又臭又长,C++11 引入一个 <code>explicit</code> 关键字直接就秒了。结果还有一批劳保教材大吹特吹 safe-bool idiom,吹得好像是个什么高大上的设计模式一样,不过是个应付 C++98 语言缺陷的蹩脚玩意。</p>
182+
</blockquote>
183+
<p>就好比一个<strong>老外</strong>想要学习汉语,他首先肯定是从<strong>现代汉语</strong>学起!而不是上来就教他<strong>文言文</strong></p>
184+
<blockquote>
185+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 即使这个老外的职业就是“考古”,或者他对“古代文学”感兴趣,也不可能自学文言文的同时完全跳过现代汉语。</p>
186+
</blockquote>
187+
<p>当我们学习中文时,你肯定希望先学现代汉语,再学文言文,再学甲骨文,再学 brainf*<em>*</em>k,而不是反过来。</p>
188+
<p>对于 C++ 初学者也是如此:我们首先学会简单明了的,符合现代人思维的 C++23,再逐渐回到专为伺候“古代开发环境”的 C++98。</p>
189+
<p>你的生产环境可能不允许用上 C++20 甚至 C++23 的新标准。</p>
190+
<p>别担心,小彭老师教会你 C++23 的正常写法后,会讲解如何在 C++14、C++98 中写出同样的效果。</p>
191+
<p>这样你学习的时候思路清晰,不用被繁琐的 C++98 “奇技淫巧”干扰,学起来事半功倍;但也“吃过见过”,知道古代 C++98 的应对策略。</p>
192+
<blockquote>
193+
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 目前企业里主流使用的是 C++14 和 C++17。例如谷歌就明确规定要求 C++17。</p>
194+
</blockquote>
195+
<h2 id="_4">举个例子</h2>
196+
<blockquote>
197+
<p><img src="../img/book.png" height="30px" width="auto" style="margin: 0; border: none"/> 接下来的例子你可能看不懂,但只需要记住这个例子是向你说明:越是新的 C++ 标准,反而越容易学!</p>
198+
</blockquote>
199+
<p>例如,在模板元编程中,要检测一个类型 T 是否拥有 <code>foo()</code> 这一成员函数。如果存在,才会调用。</p>
200+
<p>在 C++20 中,可以使用很方便的 <code>requires</code> 语法,轻松检测一个表达式是否能合法通过编译。如果能,<code>requires</code> 语句会返回 <code>true</code>。然后用一个 <code>if constexpr</code> 进行编译期分支判断,即可实现检测到存在则调用。</p>
201+
<pre><code class="language-cpp">template &lt;class T&gt;
202+
void try_call_foo(T &amp;t) {
203+
if constexpr (requires { t.foo(); }) {
204+
t.foo();
205+
}
206+
}
207+
</code></pre>
208+
<p>但仅仅是回到 C++17,没有 <code>requires</code> 语法,我们只能自己定义一个 trait 类,并运用烦人的 SFINAE 小技巧,检测表达式是否的合法,又臭又长。</p>
209+
<pre><code class="language-cpp">template &lt;class T, class = void&gt;
210+
struct has_foo {
211+
inline constexpr bool value = false;
212+
};
213+
214+
template &lt;class T&gt;
215+
struct has_foo&lt;T, std::void_t&lt;decltype(std::declval&lt;T&gt;().foo())&gt;&gt; {
216+
inline constexpr bool value = true;
217+
};
218+
219+
template &lt;class T&gt;
220+
void try_call_foo(T &amp;t) {
221+
if constexpr (has_foo&lt;T&gt;::value) {
222+
t.foo();
223+
}
224+
}
225+
</code></pre>
226+
<p>如果回到 C++14,情况就更糟糕了!<code>if constexpr</code> 是 C++17 的特性,没有他,要实现编译期分支,我们就得用 <code>enable_if_t</code> 的 SFINAE 小技巧,需要定义两个 try_call_foo 函数,互相重载,才能实现同样的效果。</p>
227+
<pre><code class="language-cpp">template &lt;class T, class = void&gt;
228+
struct has_foo {
229+
static constexpr bool value = false;
230+
};
231+
232+
template &lt;class T&gt;
233+
struct has_foo&lt;T, std::void_t&lt;decltype(std::declval&lt;T&gt;().foo())&gt;&gt; {
234+
static constexpr bool value = true;
235+
};
236+
237+
template &lt;class T, std::enable_if_t&lt;has_foo&lt;T&gt;::value, int&gt; = 0&gt;
238+
void try_call_foo(T &amp;t) {
239+
t.foo();
240+
}
241+
242+
template &lt;class T, std::enable_if_t&lt;!has_foo&lt;T&gt;::value, int&gt; = 0&gt;
243+
void try_call_foo(T &amp;) {
244+
}
245+
</code></pre>
246+
<p>如果回到 C++11,情况进一步恶化!<code>enable_if_t</code> 这个方便的小助手已经不存在,需要使用比他更底层的 <code>enable_if</code> 模板类,手动取出 <code>::type</code>,并且需要 <code>typename</code> 修饰,才能编译通过!并且 <code>void_t</code> 也不能用了,要用逗号表达式小技巧才能让 decltype 固定返回 void……</p>
247+
<pre><code class="language-cpp">template &lt;class T, class = void&gt;
248+
struct has_foo {
249+
static constexpr bool value = false;
250+
};
251+
252+
template &lt;class T&gt;
253+
struct has_foo&lt;T, decltype(std::declval&lt;T&gt;().foo(), (void)0)&gt; {
254+
static constexpr bool value = true;
255+
};
256+
257+
template &lt;class T, typename std::enable_if&lt;has_foo&lt;T&gt;::value, int&gt;::type = 0&gt;
258+
void try_call_foo(T &amp;t) {
259+
t.foo();
260+
}
261+
262+
template &lt;class T, typename std::enable_if&lt;!has_foo&lt;T&gt;::value, int&gt;::type = 0&gt;
263+
void try_call_foo(T &amp;) {
264+
}
265+
</code></pre>
266+
<p>如果回到 C++98,那又要罪加一等!<code>enable_if</code> 和 是 C++11 引入的 <code>&lt;type_traits&gt;</code> 头文件的帮手类,在 C++98 中,我们需要自己实现 <code>enable_if</code>…… <code>declval</code> 也是 C++11 引入的 <code>&lt;utility&gt;</code> 头文件中的帮手函数……假设你自己好不容易实现出来了 <code>enable_if</code><code>declval</code>,还没完:因为 constexpr 在 C++98 中也不存在了!你无法定义 value 成员变量为编译期常量,我们只好又用一个抽象的枚举小技巧来实现定义类成员常量的效果。</p>
267+
<pre><code class="language-cpp">template &lt;class T, class = void&gt;
268+
struct has_foo {
269+
enum { value = 0 };
270+
};
271+
272+
template &lt;class T&gt;
273+
struct has_foo&lt;T, decltype(my_declval&lt;T&gt;().foo(), (void)0)&gt; {
274+
enum { value = 1 };
275+
};
276+
277+
template &lt;class T, typename my_enable_if&lt;has_foo&lt;T&gt;::value, int&gt;::type = 0&gt;
278+
void try_call_foo(T &amp;t) {
279+
t.foo();
280+
}
281+
282+
template &lt;class T, typename my_enable_if&lt;!has_foo&lt;T&gt;::value, int&gt;::type = 0&gt;
283+
void try_call_foo(T &amp;) {
284+
}
285+
</code></pre>
286+
<p>如此冗长难懂的抽象 C++98 代码,仿佛是“加密”过的代码一样,仅仅是为了实现检测是否存在成员函数 foo……</p>
287+
<blockquote>
288+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 如果回到 C 语言,那么你甚至都不用检测了。因为伟大的 C 语言连成员函数都没有,何谈“检测成员函数是否存在”?</p>
289+
</blockquote>
290+
<p>反观 C++20 的写法,一眼就看明白代码的逻辑是什么,表达你该表达的,而不是迷失于伺候各种语言缺陷,干扰我们学习。</p>
291+
<pre><code class="language-cpp">void try_call_foo(auto &amp;t) {
292+
if constexpr (requires { t.foo(); }) {
293+
t.foo();
294+
}
295+
}
296+
</code></pre>
297+
<p>// 从残废的 C++98 学起,你的思维就被这些无谓的“奇技淫巧”扭曲了,而使得真正应该表达的代码逻辑,淹没在又臭又长的古代技巧中。
298+
// 从现代的 C++23 学起,先知道正常的写法“理应”是什么样。工作中用不上 C++23?我会向你介绍,如果要倒退回 C++14,古代人都是用什么“奇技淫巧”实现同样的效果。
299+
// 这样你最后同样可以适应公司要求的 C++14 环境。但是从 C++23 学起,你的思维又不会被应付古代语言缺陷的“奇技淫巧”扰乱,学起来就事半功倍。</p>
300+
<blockquote>
301+
<p><img src="../img/awesomeface.png" height="30px" width="auto" style="margin: 0; border: none"/> 既然现代 C++ 这么好,为什么学校不从现代 C++ 教起,教起来还轻松?因为劳保老师保,懒得接触新知识,认为“祖宗之法不可变”,“版号稳定压倒一切”。</p>
302+
</blockquote></div>
142303
</div>
143304
</div>
144305

platform/index.html

-4
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
<a href=".." class="dropdown-item">小彭老师现代 C++ 大典</a>
5151
</li>
5252

53-
<li>
54-
<a href="../start/" class="dropdown-item">前言</a>
55-
</li>
56-
5753
<li>
5854
<a href="../helloworld/" class="dropdown-item">你好,世界</a>
5955
</li>

0 commit comments

Comments
 (0)