![](https://img-blog.csdnimg.cn/20190927151117521.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
《Effective Modern C++》读书笔记
文章平均质量分 62
理解Effective Modern C++可不只是熟悉它们引入的特性(例如,auto类型声明,移动语义,lambda表达式和并行计算支持)这么简单.挑战在于学习如何高效应用这些特性——让你的软件正确,有效,易于维护和可移植.这就是这本具有很强实践性的书籍的目的所在.本书描述了如何使用Effecti
Chiang木
这个作者很懒,什么都没留下…
展开
-
《Effective Modern C++》学习笔记之条款四十二:考虑置入而非插入
如果你有个容器,持有一些,比如说,std::string型别的对象,那么似乎合乎逻辑的做法是用某个插入函数insertion function来向其中添加新元素,比如insert,push_front和push_back,又或者对于std::forward_list而言的insert_after,而传递给函数的元素型别将是std::string。毕竟,那正是容器持有物的型别。1. 分析为什么push_back效率不高说合乎逻辑倒也确实合乎逻辑,但却不一定合乎事实。考虑这段代码:std::vect原创 2022-03-20 13:26:02 · 6723 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款四十一:针对可复制的形参,在移动成本低并且一定会被复制的前提下,考虑将其按值传递
C++中的每一项通用技术或特性,都会在某些情况下使用,而在另一些情况下则不适用。一般而言,描述通用技术或者特性的适用情况才顺理成章,但本章却反其道而行之,描述了两种例外情况。通用技术指的是按值传递,而通用特性则是置入(emplacement)。想做出是否采用它们的决定,须面对诸多影响因素,而我能够提供的最佳建议则是需要考虑他们其实是有适用场景的。话虽如此,这两者可都是高效现代C++程序设计的重要角色,下面的条款为在评价它们是否适用你的软件这方面提供了参考信息。方法一:重载有些函数的形参本来就是打原创 2022-03-20 13:14:35 · 252 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款四十:对并发使用std::atomic,对特种内存使用volatile
可怜的volatile。被误解到如此地步。它甚至不应该出现在本章中,因为它与并发程序设计毫无关系。但是在其他程序设计语言中(例如 Java 和 C# ),它还是会对并发程序设计有些用处。甚至在C++中,一些编译器也已经把volatile投入了染缸,使得它的语义显得可以用于并发软件中(但是仅可能用于使用这些编译器进行编译之时)。因此,除了消除环绕在它周围的混淆视听外,没有什么其他的理由值得在关于并发的一章中讨论volatile。程序员有时会把volatile与绝对属于本章讨论范围的另一C++特性混淆,原创 2022-03-20 13:04:34 · 1891 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十九:考虑针对一次性事件通信使用以void为模板型别实参的期值
有时候,提供让一个任务通知另一个以异步方式运行的任务发生了特定的事件的能力,会很有用,原因可能是第二个任务在事件发生之前无法推进。这事件也许是某个数据结构完成了初始化,也许是某个计算阶段结束了,又也许是某个重要传感器取值被检测到了等等。在此情况下,用什么方式完成线程间通信会是最佳的呢?1. 使用条件变量一种明显的途径是使用条件变量,若我们把检测条件的任务成为检测任务,把对条件做出反应的任务成为反应任务,则策略表述起来很简答:反应任务等待这条件变量,而检测任务则在事件发生时,通知条件变量。给定:.原创 2022-03-20 12:52:35 · 345 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十八:对变化多端的线程句柄析构函数行为保持关注
Item 37 解释过,可联结的线程对应着一个底层系统执行线程,未推迟任务(参见Item 36)的期值和系统线程也有类似关系。这么一来,std::thread型别对象和期值对象都可以视作系统线程的句柄。从这个视角看,std::thread对象和期值独享的析构函数表现出如此不同的行为值得深思。重温std::thread的析构表现Item 37 中剃刀的,针对可联结的std::thread型别对象实施析构会导致程序终止,因为另外两个显而易见的选择(隐式join或者detach)都被认为是更糟糕的选择原创 2022-03-19 19:15:11 · 223 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十七:使std::thread型别对象在所有路径皆不可联结
每个std::thread型别对象皆处于两种状态之一:可联结或不可联结。哪些属于可联结可联结的std::thread对应底层以异步方式已运行或者可运行的线程。std::thread型别对象对应的底层线程若处于阻塞或等待调度,则它可联结。std::thread型别对象对应的底层线程如已运行结束,则也认为其可联结。哪些属于不可联结不可联结的std::thread的意思如你所想:std::thread不处于以上可联结的状态。不可联结的std::thread型别对象包括:默认构造的std::th原创 2022-03-19 19:11:55 · 334 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十六:如果异步是必要的,则指定std::launch::async
当你调用std::async来执行一个函数(或一个可执行对象)时,你通常希望函数是异步执行的。但你没有要求std::async必须这样做,函数是根据std::async的发射策略(launch policy)来执行的。有两个标准策略,每个都是通过std::launch局部枚举来表示。假设一个函数f要传递给std::launch执行,std::launch::async:意味着函数f必须异步执行,即在另一线程执行。 std::launch::deferred:意味着函数f只会在std::async所返回原创 2022-03-19 18:58:47 · 1179 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十五:优先选用基于任务而非基于线程的程序设计
如果你想以异步方式运行函数doAsyncWork(),有两种方法。你可以创建一个std::thread,并在其上运行doAsyncWork,这种方式属于基于线程的程序设计(thread_based) int doAsyncWork();std::thread t(doAsyncWork); 也可以把doAsyncWork传递给std::async,这种策略叫做基于任务(task_based) auto fut = std::async(doAsyncWork); //fut是...原创 2022-03-14 16:50:04 · 906 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十四:优先选用lambda表达式,而非std::bind
1. 先来点历史资料std::bind是C++98中std::bind1st和std::bind2nd的后继特性,但是作为一种非标准特性而言,std::bind在2005年就已经是标准库的组成部分了。正是在那时,标准委员会接受了名称TR1的文档,里面就包含了std::bind的规格(在TR1中,bind位于不同的名字空间,所以是std::tr1::bind而非std::bind,还有一些借口细节与现在有所不同)。2. 再来谈抛弃这样的历史意味着,有些开发者已经有了十多年的std::bind开发经原创 2022-03-19 16:55:03 · 276 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十三:对auto&&型别的形参使用decltype,以std::forward之
1. 你有完美转发lambda入参的需求么?泛型lambda式(generic lambda)是C++14最振奋人心的特征之一————lambda可以在形参规格中使用auto。这个特性的实现十分直接了当:闭包类中的operator()采用模板实现。例如,给定下述lambda式:auto f = [](auto x) { return func(normalize(x));};则闭包类的函数调用运算符如下所示:class SomeComilerGeneratedClassName {.原创 2022-03-19 16:37:38 · 410 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十二:使用初始化捕获将对象移入闭包
如果你有一个对象,其复制操作开销昂贵,而移动操作成本低廉,而你又需要把该对象放入闭包,那么你肯定更愿意移动该对象,而非复制它。C++14为我们提供了一个全新的捕获方式---初始化捕获,也叫做广义lambda捕获,使用初始化捕获,则你会得到机会指定: 由lambda生成的闭包类中的成员变量名字。 一个表达式,用以初始化该成员变量。 例如使用初始化捕获将std::unqiue_ptr移动到闭包内:class Widget { //一些有用的型别p原创 2022-03-15 14:02:45 · 702 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十一:避免默认捕获模式
C++11中有两种默认捕获方式:按值或者按引用。按值的默认捕获方式可能会忽悠你,按引用的默认捕获方式可能导致空悬引用。按引用捕获会导致闭包包含涉及到局部变量的引用,或者涉及到定义lambda式子的作用域内形参的引用,考虑如下代码:using FilterContainer = std::vector<std::function<bool(int)>>;FilterContainer filters;void addDivisorFilter() { auto cal原创 2022-03-14 16:09:50 · 882 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三十:熟悉完美转发的失败情形
完美转发的确切含义:“转发”的含义不过是一个函数把自己的形参传递(转发)给另一个函数而已。其目的是为了让第二个函数(转发目的函数)接受第一个函数(转发发起函数)所接受的同一对象。这就排除了按值传递形参,因为它们只是原始调用者所传递之物的副本,我们想要转发目的函数能够处理原始传入对象。指针形参也只能出局,因为我们不想强迫调用者传递指针。论及一般意义上的转发时,都是在处理形参为引用类型的情形。完美转发的含义是我们不仅转发对象,还转发显著特征:类型,是左值还有右值,以及是否带有const或volatile..原创 2022-03-14 15:23:23 · 245 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十九:假定移动操作不存在/成本高/未使用
我们知道,C++98标准库已经为C++11彻底翻修过,目的是为那些移动比复制更快的型别添加移动操作,但是如果你现有的代码没有为C++11做过专门修改,那性能也不会有很大提升。前面我们知道,C++11只会为那些未声明复制操作、移动操作以及析构函数的类生成移动操作。而且有些类的移动可能并不会比复制快多少,例如std::array这个新容器类别,它实质上就是带有STL接口的内建数组,这一点和其他容器有很大区别,其他容器都是将其内容存放在堆上,然后维护一个堆指针,当需要移动时,只需要将指针重新赋值即可,..原创 2022-03-14 14:39:23 · 798 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十八:理解引用折叠
前面我们说过,形参为万能引用型别时,将根据实参的型别来决定最终param的型别:template<class T>void func(T&& param) { //do something}Widget w;func(w); //w为左值,T为Widget&,param为Widget&func(Widget());//实参为右值,T为Widget,param为Widget&&之所以会有上面结果的推导..原创 2021-03-10 08:41:24 · 273 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十七:熟悉依万能引用型别进行重载的替代方案
上一篇避免依万能引用型别进行重载讲过使用万能引用型别进行重载可能会存在的问题, 这一篇我们就来讲讲如何规避这些问题:一、舍弃重载既然万能引用重载会有问题,那么我们就直接多写几个函数,命名成不同名字,杜绝重载就可以。二、传递const T&型别的形参使用传递左值常量引用型别来替代万能引用型别,这样在就可以限制该函数接受的参数了。三、传值如果你确定你的实参的复制操作将无可避免,可以使用传值方式来替代万能引用。四、标签分派上面几种都不支持完美转发,不是很满足效率提升的要..原创 2021-03-10 00:18:48 · 178 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十六:避免依万能引用型别进行重载
如果我们在代码中使用万能引用型别作为函数重载的一个特征标,这样在我们使用该重载函数时,实际调用的函数可能与我们期望不符:示例代码如下:#include <memory>#include <iostream>#include <set>using namespace std;//万能引用型别重载template <class T>void MaKeZiYuan(T&& t) { cout << "MaK..原创 2021-03-09 23:13:54 · 204 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十五:针对右值引用实施std::move,针对万能引用实施std::forward
我们应该知道,一个函数接受一个右值引用参数后将变成左值(可以对其取地址),所以如果在函数内部想要继续使用其右值属性,就可以对其实施std::move,将形参左值转换回右值。对于万能引用,因为其实参可能是右值,也可能是左值(最终形参都是左值),所以对其实施std::forward,实参右值将被转换回右值,实参左值将什么都不做。至于为什么不能对万能引用实施std::move,主要考虑到其实参可能是左值的情况:如果实参是左值局部变量,当我们将其转换为右值后,且赋值到成员变量上时,成员变量与局部变量是...原创 2021-03-09 00:38:49 · 197 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十四:区分万能引用和右值引用
在前面的文章讲了很多万能引用,形式如"T&&",但右值引用也可以这样表示,具体什么样的才是万能引用呢?万能引用必须涉及型别推导,且参数形式必须为“T&&”,不能带有任何其他修饰关键字(const、volatile),不是万能引用就是右值引用:template <class T>void f(T&& param); //param是一个万能引用auto&& var1 = var2; //var1是一个万能引用,只..原创 2021-03-07 23:27:31 · 192 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十三:理解std::move和std::forward
std::move()实施的是无条件的向右值型别进行强制类型转换,而std::forward仅当实参是右值时,才会将参数转换为右值,且它们都仅仅时强制类型转换,并不做移动操作。std::move()的使用场景没有什么好说的了,当你需要实参是右值时,执行该函数就对了,因为它可以百分百返回参数对应的右值。关于std::forward的使用场景,我们直接来看代码:void process(const Widget& lValue); //处理左值void process(const ...原创 2021-03-07 23:08:38 · 241 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十二:使用Pimpl习惯用法时,将特殊成员函数的定义放在实现文件中
Pimpl习惯用法指的是pointer to implementation,即指涉到实现的指针。这种技巧就是把某类的数据成员用一个指涉到某实现类的指针替代,然后把原来在主类中的数据成员放置到实现类中,并通过指针间接访问这些数据成员。示例代码://Widget.h中class Widget {public: Widget();private: class Impl; //声明结构体或类 std::unique_ptr<Impl..原创 2021-03-07 13:02:37 · 217 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十一:优先选用std::make_unique和std::make_shared,而非直接new
首先要知道, std::make_shared是C++11引入的一个make函数,而std::make_unique是C++14才引入。使用 std::make_shared及std::make_unique代替new的好处:(1)代码量更小,不需要承父撰写型别auto upw1(std::make_unique<Widget>());//重复写了两次Widget型别std::unique_ptr<Widget> upw2(new Widget);(2)可能..原创 2021-03-07 00:48:49 · 381 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二十:对于类似std::shared_ptr但有可能空悬的指针使用std::weak_ptr
std::weak_ptr一般使用std::shared_ptr来创建,但std::weak_ptr并不会增加std::shared_ptr的计数:auto spw = std::make_shared<Widget>();//spw的引用计数并不会增大std::weak_ptr wpw(spw);若上述代码中的spw被析构,则wpw将空悬,可以使用std::weak_ptr的成员函数expired()进行判断。但请注意expired()是非原子操作,所以其结果不一定准确,可..原创 2021-03-07 00:03:47 · 220 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十九:使用std::shared_ptr管理具备共享所有权的资源
std::shared_ptr通过引用计数的方式实现资源共享,当计数为0时,资源将被释放。std::shared_ptr的尺寸是裸指针的两倍,因为其内部除了包含了一个指涉到该资源的裸指针,还包含一个指涉到该资源的一个控制块的裸指针,该控制块为动态分配在堆上,内容包含:引用计数、弱计数、自定义删除器、自定义分配器等。我们在对std::shared_ptr的引用计数进行操作时,其成本是很高的,因为这个是原子操作。当我们对一个std::shared_ptr进行移动构造时,实际上是非常迅速的,因为这个操..原创 2021-03-06 23:13:49 · 502 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十八:使用std::unique_ptr管理具备专属所有权的资源
当需要使用智能指针时,std::unique_ptr基本上应当是首选,因为默认情况下std::unique_ptr和裸指针有着相同的尺寸,且对于大多数的操作(包括提领),他们都是精确的执行了相同的指令。std::unique_ptr实现的是专属所有权语义,其只支持移动,不支持复制,也不能将一个裸指针直接赋值给std::unique_ptr对象,编译器禁止这种隐式转换。默认的std::unique_ptr的析构函数将调用delete完成指针删除操作,当然,如果默认的析构函数不满足要求,我们也可以自定...原创 2021-03-06 15:41:57 · 297 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十七:理解特种成员函数的生成机制
这里所说的特种成员函数包括C++98已有的默认拷贝函数、析构函数、复制构造函数、复制赋值运算符以及C++11新增的移动构造函数以及移动赋值运算符。这些特种成员函数在特定场合,编译器都可以自动为其生成,且访问权限都是public的,inline类型的。以下几点是特种成员函数生成的特点:仅当一个类没有声明任何构造函数时,编译器才会自动生成默认构造函数。 当基类的析构函数是虚函数时,编译器为子类生成的默认析构函数也才会是虚函数,且析构函数默认为noexcept的。 默认的移动构造函数以及移动赋值...原创 2021-03-05 00:06:33 · 239 阅读 · 1 评论 -
《Effective Modern C++》学习笔记之条款十六:保证const成员函数的线程安全性
我们知道const成员函数不会修改成员变量,即对变量进行只读操作,但是即使是只读,其函数真的是安全的吗?例如,我们在一个成员函数内获取某个对象的一个变量的值,其值在第一次和第二次读取有差异,代码如下:class MyClass{public: void Init() const { if (!InitFlag) { //.... 执行一系列操作 InitFlag = true; } }privat..原创 2021-03-03 00:26:25 · 326 阅读 · 1 评论 -
《Effective Modern C++》学习笔记之条款十五:只要有可能使用constexpr,就使用它
constexpr变量必须使用一个具有const属性,且在编译阶段就已知的值对其初始化。例如:int x = 0;const int y = x; //可以使用x对cosnt变量初始化const int z = 0; constexpr int arraySize = x; //错误,x为运行期间才确定值的变量constexpr int arraySize = y; //错误,y为运行期间才确定值的变量constexpr int arraySize = z; //正确,..原创 2021-03-01 00:18:14 · 279 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十四:只要函数不会发射异常,就为其加上noexcept声明
首先,如果知道一个函数不可能抛出异常,则应该将其声明为noexcept,以提高代码的运行效率,但是如果函数却违法声明抛出了异常将导致程序直接中止。在C++98和C++11中都可以声明一个函数不会抛出异常,代码如下:int f(int x) throw(); //f不会抛出异常,C++98风格int f(int x) noexcept; //f不会抛出异常,C++11风格而使用noexcept而非throw()好处有一下几个原因:声明为nocept,优化器会对函数做最大值的优化,包括..原创 2021-02-28 23:28:57 · 268 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十三:优先选用const_iterator,而非iterator
在C++98中 const_iterator得到的支持不够全面,使用起来相当费力,C++11对其做了一个很大的优化,但是仍然有死角,但是C++14将这些死角清除干净了,所以现在我们可以很好的使用它。首先我们要记住的是在C++11中无法将iterator强制转换为const_iterator,即使是static_cast或者reinterpret_cast也不行。如果我们要获取const_iterator类型迭代器,在C++11中很简单,只需要使用对象调用其成员函数cbegin()或cend()即..原创 2021-02-28 22:13:12 · 195 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十二:为意在改写的函数后添加override声明
override声明的作用很简单,就是当你为子类改写从父类那里继承下来的成员函数时,如果因为各种原因,导致改写失败(失败原因有很多,例如形参类型错误、函数修饰词遗漏等等),将在编译时给你明确提示。要点速记为意在改写的函数后添加override声明 成员函数左值引用修饰词(&)及右值引用修饰词(&&)是的对于左值对象及右值对象(*this)的处理能够区分开来。...原创 2021-02-28 21:51:18 · 254 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十一:优先选用delete删除函数,而非private未定义函数
如果你实现了某个类给其他程序猿使用,但是不想让他使用某个特定函数,那我们可以直接不声明该函数即可。但是如果这个函数是编译器自动生成的,例如默认赋值函数,那我们又应该怎么做呢?C++98中的做法是将该函数声明为private权限,这样就阻止了外部直接调用它,然后我们也不去定义它,这样当该类的成员函数误调用该函数时,会提示链接错误。例如:class Test {public: void Fix(Test& t) { Test t1; t1 = t;..原创 2021-02-28 14:05:34 · 357 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款十:优先选用限定作用域的枚举类型,而非不限作用域的枚举类型
首先通过两行代码了解,什么是限定作用域的枚举类型,什么是不限作用域的枚举类型。enum Color{black,white,red}; //不限作用域的枚举类型 enum class Color{black,white,red}; //限定作用域的枚举类型,多了一个class关键字优先使用限定作用域的枚举类型的原因有三个:1、降低名字空间污染。防止枚举值名称与变量名冲突。//不限作用域的枚举类型 enum Color{black,white,red}; aut..原创 2021-02-27 22:49:27 · 201 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款九:优先选用别名声明,而非typedef
using别名声明和typedef声明都可以完成一个类型的声明,但使用using可以很简单且直接的完成这个操作,下面将通过代码分别声明相同的类型,就可以看出using的好处了。//声明指针函数typedef void(*FP)(int ,double); //typedef晦涩不直白using FP = void(*)(int ,double); //using简单直白//typedef声明一个模板,表示一个链表template<class T>struct MyAl..原创 2021-02-27 20:48:15 · 192 阅读 · 1 评论 -
《Effective Modern C++》学习笔记之条款八:优先选用nullptr,而非0或NULL
0就是int类型,在一些场合下,勉勉强强可以解释为空指针,但记住这是不得已场景下才会这么做。NULL在不同系统中会有不同的类型实现,有的是int,有的是long,其本质也是一个整型。但是nullptr就不一样了,虽然它的本质是std::nullptr_t,但是因为其可以隐式转换到所有类型的裸指针型别。所以在函数重载时,nullptr可以完美匹配指针型别的重载函数:void f(int);void f(bool);void f(void*);f(0); //匹配到void f(int)..原创 2021-02-27 20:23:34 · 148 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款七:在创建对象时注意区分()和{}
对象初始化的方式有很多种,特别是C++11新引入了统一初始化,可以用于一切场合的初始化,至少从概念上可以这么理解。目前常见的初始化方式大概有以下几种:int x(0); //使用小括号初始化int y = 0; //使用等号初始化int z{0}; //使用C++11新引入的统一初始化格式,即大括号初始化int z1 = {0};//统一初始化格式变体,编译器对其处理完全无差别C++11新引入了统一初始化方式可以处理很多C++98无法完成的工作,例如:(1)给一个ST..原创 2021-02-26 00:11:00 · 222 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款六:当auto推导的型别不符合要求时,使用带显示型别的初始化
虽然auto用起来确实好处多多,到那时也并不是万能的,在有些场景下,我们就不得不使用带显示型别的初始化。例如如下代码:std::vector<bool> features() { std::vector<bool> temp; for(int i = 0;i < 10; ++i) { temp.push_back(true); } return temp;}auto result = feat..原创 2021-02-25 00:00:43 · 169 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款五:优先选用auto,而非显示型别声明
废话补多少,直接总结一下使用auto的好处:1、对于变量未初始化情况,如果使用显示显示型别声明,程序猿将无感知,但是如果使用了auto进行变量声明,将提醒你编译错误。int x1; //有潜在的未初始化风险auto x2; //未初始化,编译报错2、简化代码,特别时迭代器相关的,能够省略很大的代码量3、对于某些lambda表达式,我们应使用auto变量来接收它,而非std::function,因为无论从效率还是代码整洁度方面,auto都是完胜//应使用auto而非std::f..原创 2021-02-24 00:16:26 · 286 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款三:理解decltype
decltype是C++11新增的一个关键字,它的主要应用场景是哪些返回值依赖于形参型别的场景。一般来说decltype告诉你的结果与你预测的几乎相同,所以这里就不再累述,只需要记住以下几点即可:decltype(expression) var; 具体判断逻辑如下:(1)如果expression没有使用括号括起来,则类型与expression完全相同,例如 const int i =0; decltype(i) var;则var为const int.(2)如果expression是一个函数调用,则v..原创 2021-02-23 23:05:10 · 306 阅读 · 0 评论 -
《Effective Modern C++》学习笔记之条款二:理解auto型别推导
首先auto型别推导与模板型别推导完全相同,唯一的区别是在对大括号括起来的表达式进行推导时,auto会将其推导为一个std::initializer_list的类型。代码示例如下:auto x1 = 27; //x1型别为intauto x2(27); //x2型别为intauto x3 = {27}; //x3型别为std::initializer_list<int>auto x4{27}; //x4型别为std::initializer_list<..原创 2021-02-22 23:30:30 · 274 阅读 · 0 评论