![](https://img-blog.csdnimg.cn/2020071422085326.jpg?x-oss-process=image/resize,m_fixed,h_224,w_224)
Effective Modern C++ 读书笔记
文章平均质量分 94
本专栏是阅读Scott Meyers著的Effective Modern C++ 的读书笔记,精炼了本书部分内容,引用了本书诸多示例代码。
我才是鳴海步
新显实验室毕业的机械专业程序猿
展开
-
Effective Modern C++ Item 42 考虑置入而非插入
如果你有个容器,持有一些,比如说,`std::string`型别的对象,那么似乎合乎逻辑的做法是用某个插入函数`insertion function`来向其中添加新元素,比如`insert`,`push_front`和`push_back`,又或者对于`std::forward_list`而言的`insert_after`,而传递给函数的元素型别将是`std::string`。毕竟,那正是容器持有物的型别。原创 2021-12-04 19:37:04 · 1101 阅读 · 0 评论 -
Effective Modern C++ Item 41 针对可复制的形参,在移动成本低并且一定会被复制的前提下,考虑将其按值传递
C++中的每一项通用技术或特性,都会在某些情况下使用,而在另一些情况下则不适用。一般而言,描述通用技术或者特性的适用情况才顺理成章,但本章却反其道而行之,描述了两种例外情况。通用技术指的是按值传递,而通用特性则是置入(emplacement)。想做出是否采用它们的决定,须面对诸多影响因素,而我能够提供的最佳建议则是需要考虑他们其实是有适用场景的。话虽如此,这两者可都是高效现代C++程序设计的重要角色,下面的条款为在评价它们是否适用你的软件这方面提供了参考信息。方法一:重载有些函数的形参本来就是打算拿.原创 2021-10-21 19:54:07 · 364 阅读 · 0 评论 -
Effective Modern C++ Item 40 对并发使用std::atomic,对特种内存使用volatile
可怜的volatile。被误解到如此地步。它甚至不应该出现在本章中,因为它与并发程序设计毫无关系。但是在其他程序设计语言中(例如 Java 和 C# ),它还是会对并发程序设计有些用处。甚至在C++中,一些编译器也已经把volatile投入了染缸,使得它的语义显得可以用于并发软件中(但是仅可能用于使用这些编译器进行编译之时)。因此,除了消除环绕在它周围的混淆视听外,没有什么其他的理由值得在关于并发的一章中讨论volatile。程序员有时会把volatile与绝对属于本章讨论范围的另一C++特性混淆,那.原创 2021-09-18 21:17:34 · 350 阅读 · 0 评论 -
Effective Modern C++ Item 39 考虑针对一次性事件通信使用以void为模板型别实参的期值
有时候,提供让一个任务通知另一个以异步方式运行的任务发生了特定的事件的能力,会很有用,原因可能是第二个任务在事件发生之前无法推进。这事件也许是某个数据结构完成了初始化,也许是某个计算阶段结束了,又也许是某个重要传感器取值被检测到了等等。在此情况下,用什么方式完成线程间通信会是最佳的呢?1. Solution 1 使用条件变量一种明显的途径是使用条件变量,若我们把检测条件的任务成为检测任务,把对条件做出反应的任务成为反应任务,则策略表述起来很简答:反应任务等待这条件变量,而检测任务则在事件发生时,通知条.原创 2021-08-31 10:16:23 · 267 阅读 · 0 评论 -
Effective Modern C++ Item 38 对变化多端的线程句柄析构函数行为保持关注
Item 37 解释过,可联结的线程对应着一个底层系统执行线程,未推迟任务(参见Item 36)的期值和系统线程也有类似关系。这么一来,std::thread型别对象和期值对象都可以视作系统线程的句柄。从这个视角看,std::thread对象和期值独享的析构函数表现出如此不同的行为值得深思。重温std::thread的析构表现Item 37 中剃刀的,针对可联结的std::thread型别对象实施析构会导致程序终止,因为另外两个显而易见的选择(隐式join或者detach)都被认为是更糟糕的选择。期原创 2021-04-13 21:12:15 · 201 阅读 · 0 评论 -
Effective Modern C++ Item 37 使std::thread型别对象在所有路径皆不可联结
每个std::thread型别对象皆处于两种状态之一:可联结或不可联结。哪些属于可联结可联结的std::thread对应底层以异步方式已运行或者可运行的线程。std::thread型别对象对应的底层线程若处于阻塞或等待调度,则它可联结。std::thread型别对象对应的底层线程如已运行结束,则也认为其可联结。哪些属于不可联结不可联结的std::thread的意思如你所想:std::thread不处于以上可联结的状态。不可联结的std::thread型别对象包括:默认构造的std::threa原创 2021-03-20 09:09:08 · 203 阅读 · 0 评论 -
Effective Modern C++ Item 36 如果异步是必要的,则指定 std::launch::async
当调用std::async来执行一个函数(或可调用对象)时,你基本上都会想让函数以异步方式运行。但仅仅通过std::async来运行,你实际上要求的并非一定会达成异步运行的结果,你要求的仅仅是让该函数以符合std::async的启动策略来运行。标准策略有两个,他们都是用限定作用域的枚举型别std::launch中的枚举量(关于限定作用域的枚举,参见Item 10)来表示的。假设函数f要传递给std::async以执行,则:std::launch::async启动策略意味着函数f必须以异步方式运行,.原创 2021-03-12 19:31:30 · 209 阅读 · 0 评论 -
Effective Modern C++ Item 35 优先选用基于任务而非基于线程的程序设计
如果你想以异步方式运行函数doAsyncWork,有两种方法。你可以创建一个std::thread,并在其上运行doAsyncWork,这种方式属于基于线程的途径(thread_based)int doAsyncWork();std::thread t(doAsyncWork);你可以把doAsyncWork传递给std::async,这种策略叫做基于任务(task_based)auto fut = std::async(doAsyncWork); //fut是期望的缩写基于任务原创 2021-03-11 20:53:57 · 216 阅读 · 0 评论 -
Effective Modern C++ Item 34 优先选用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开发经验。如原创 2020-12-24 11:09:53 · 368 阅读 · 0 评论 -
Effective Modern C++ Item 33 对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 {public:原创 2020-12-23 15:33:53 · 224 阅读 · 0 评论 -
Effective Modern C++ Item 32 使用初始化捕获将对象移入闭包
有时,按值的捕获和按引用的捕获皆非你所欲。如果你想要把一个只移对象(例如,std::unique_ptr或std::future型别的对象)放入闭包,C++11未提供任何办法做到此事。如果你有一个对象,其复制操作开销昂贵,而移动操作成本低廉(例如,大部分标准库容器0),而你又需要把该对象放入闭包,那么你肯定更愿意移动该对象,而非复制它。但是,C++11中也还是没有让你实现这一点的途径。1. C++14 提供的移动捕获,与C++11的模拟移动捕获但那只是C++11,C++14则有云泥之别。它为对象移动入闭原创 2020-12-22 15:55:23 · 376 阅读 · 0 评论 -
Effective Modern C++ Item 31 避免默认捕获模式
C++11中有两种默认捕获模式:按引用或按值。按引用的默认捕获模式可能导致空悬引用,按值的默认捕获模式会忽悠你,好像可以对空悬引用免疫(其实并没有),还让你认为你的闭包是独立的(事实上它们可能不是独立的)。以上就是本条的重点内容。1. 默认捕获模式的危害按引用捕获会导致闭包包含指涉到局部变量的引用,或者指涉到定义lambda式的作用于内的形参的引用。一旦由lambda式锁创建的闭包越过了该局部变量或形参的生命期,那么闭包内的引用就会空悬。例如,我们有一个元素为筛选函数的容器,其中每个筛选函数都接受.原创 2020-12-21 22:03:35 · 261 阅读 · 2 评论 -
Effective Modern C++ Item 30 熟悉完美转发的失败情形
在C++11的中最引人瞩目的语言特性之一,就是完美转发。完美转发,可是完美的哟!不过,解开这完美的外表,你才会发现理想和现实有差距。C++11的完美转发相当不错,但如果一定要说达到了完美,那还是有一定差距的。本节主要介绍这些差距的地方。转发的使用背景先考虑一下完美转发的确切含义。“转发”的含义不过是一个函数把自己的形参传递(转发)给另一个函数而已。其目的是为了让第二个函数(转发目的函数)接受第一个函数(转发发起函数)所接受的同一对象。这就排除了按值传递形参,因为他们只是原始调用者锁传递之物的副本。我们想原创 2020-12-01 23:00:30 · 276 阅读 · 0 评论 -
Effective Modern C++ Item 29 假定移动操作不存在,成本高,未使用
传说中高效的移动操作移动语义在C++11的所有语言特性中,占据首要地位。移动容器现在和复制指针一样成本低廉了!你很有可能听说过,类似的说法还有:复制临时对象现在已经如此高效,如果可以在撰写代码中避免它,就无异于犯了过早优化的禁忌!这些情绪化的言辞不难理解。移动语义确实是个重要的语言特性。语言不只是允许编译器使用成本相对低廉的移动操作来代替昂贵的复制操作,实际上语言会要求编译器这样做(只要满足适当条件就必须这样做)。调出你的C++98版本代码,然后只需要一字不改地使用符合C++11标准的编译原创 2020-11-23 15:01:22 · 192 阅读 · 0 评论 -
Effective Modern C++ Item 28 理解引用折叠
Item 23 曾经提到,实参在传递给函数模板时,推导出来的模板形参会将实参是左值还是右值的信息编码到结果型别中。但此条款未曾提到,这个编码操作只有在实参被用用以初始化的形参为万能引用时,才会发生。不过,有一个充分的理由来解释为什么当时不提及这些:万能引用是在Item24中才介绍。把万能引用和左右值编码信息的论述综合起来,意思就是,按照下面这个模板为例:template<typename T>void func(T&& param);模板形参T的推导结果型别中,会把传递原创 2020-11-02 15:46:00 · 244 阅读 · 0 评论 -
Effective Modern C++ Item 27 熟悉依万能引用型别进行重载的替代方案
Item 27 熟悉依万能引用型别进行重载的替代方案Item 26说过,万能引用和重载在一起总会产生各种各样的问题,无论是独立函数,成员函数,都最好不要和万能引用放一起重载,其中构造函数和万能引用放一起问题最为严重。不过实际业务中其实的确有这样的真实需求。本条款对这种需求的解决方案进行了探讨。提出了几种合适的解决方案。目的在于获得期望的行为,方法。以下各个手法均以Item 26中构建的代码为基础的,如果没看或者不熟悉,那么先了解一下再继续下去。放弃重载Item 26的第一个例子,logAndAdd,原创 2020-10-15 09:59:41 · 408 阅读 · 0 评论 -
Effective Modern C++ Item 26 避免依万能引用型别进行重载
一个常见的业务背景假设一个业务场景是这样的:取用一个名字作为形参,然后记录下当前时间,在把该名字添加到一个全局数据结构中。也许你会这样实现:std::multiset<std::string> names; //全局数据结构void logAndAdd(const std::string name){ auto now = std::chrono::system_clock::now(); //获取当前时间 log(now, "logAndA原创 2020-09-07 15:07:51 · 246 阅读 · 0 评论 -
Effective Modern C++ Item 25 针对右值引用实施std::move,针对万能引用使用std::forward
右值引用仅仅会绑定到那些可供移动的对象上,如果形参为右值引用,则应该清楚了解,它绑定的对象可供移动:class Widget { Widget(Widget&& rhs); //rhs确定无疑会绑定到可以移动的对象上}如果,当你希望把这些对象传递给其他函数时,使用一种允许该函数利用该对象的右值性的方式。那么你可以使用这样的方法:把绑定到这些对象的形参转换为右值。而正如Item 23中介绍的,这不仅仅是std::move能够胜任的工作,也是std::move被设计出原创 2020-08-31 11:36:41 · 361 阅读 · 0 评论 -
Effective Modern C++ Item 24 区分万能引用和右值引用
当你看到T&&,可能会把它当做一个右值引用。但实际上事情没有那么简单,看如下代码:void f(Widget&& param); //右值引用Widget&& var1 = Widget(); //右值引用auto&& var2 = var1; //非右值引用template<typename T>void f(std::vector<T>&&a原创 2020-08-06 16:37:17 · 348 阅读 · 0 评论 -
Effective Modern C++ Item 23 理解std::move和std::forward
std::move并不进行任何移动 std::forward 并不进行任何转发这两者在运行期都没有任何作为,不会产生任何可执行代码,连一个字节都不会生成。std::move 和 std::forward 都仅仅是执行强制型别转换的函数(实际上是函数模板)std::move 无条件将实参强制转换成右值。std::forward仅在特点条件满足时,才执行同一个强制转换。实际上本章所有内容就这么多,但如果要说的更具体些的话。再开始之前,需要记住这样一点:所有形参都是左值,即便形参的型别是.原创 2020-08-06 14:42:57 · 232 阅读 · 0 评论 -
Effective Modern C++ Item 22 适用Pimpl习惯用法时,将特殊成员函数的定义放到实现文件中
如果你有和过长构建时间的抗争经历,那么你应该熟悉Pimpl习惯用法。这种技巧就是把某类的数据成员用一个指涉到某实现类的指针代替,然后把原来在主类中的数据成员放置到实现类中,并通过指针间接访问这些数据成员。例如考虑某Widget类如下:class Widget { //位于头文件"widget.h"内public: Widget(); ...private: std::string name; std::vector<double>原创 2020-08-04 16:38:57 · 309 阅读 · 0 评论 -
Effective Modern C++ Item 21 优先选用std::make_unique和std::make_shared,而非直接使用new
这里我们把std::make_unique和std::make_shared放到同一起跑线作为本条款的开端。如果您使用的是C++11没有std::make_unique也没事,下面的代码很容易将生成这个功能:template<typename T, typename ... Ts>std::unique_ptr<T> make_unique(TS&&... params){ return std::unique_ptr<T>(new T(st原创 2020-08-03 20:11:29 · 304 阅读 · 0 评论 -
Effective Modern C++ Item 20 对于类似std::shared_ptr但有可能悬空的指针,使用std::weak_ptr
如果需要某种智能指针能够像std::shared_ptr一样方便,但又无需参与管理所指涉到的对象的共享所有权的话。就很好适合用std::weak_ptr。但这样的功能同样会带来一个问题。这种指针需要处理一个对std::shared_ptr而言不是问题的问题:所指涉的对象有可能已经被析构。而std::weak_ptr的确是可以判断所指向对象是否还存在。std::weak_ptr的用途在看完std::weak_ptr的API后,你可能会困惑,这东西不能取地址,也不能检查是否为空。这东西到底有什么用呢。其实原创 2020-08-03 16:51:18 · 255 阅读 · 0 评论 -
Effective Modern C++ Item 19 使用std::shared_ptr管理具备共享所有权的资源
std::shared_ptr让C++程序猿有了垃圾回收机制,std::shared_ptr采用的引用计数法做的垃圾回收。虽然不如根搜索算法那样,可以防止相互引用无法释放,但比起之前已经是飞跃了。引用计数法:通常构造的时候+1引用计数,析构的时候-1引用计数。引用计数为0的时候,真正释放此对象。引用计数法会带来一些性能影响:std::shared_ptr的尺寸是裸指针的两倍。它们内部包含一个直射到该资源的裸指针,也包含一个指涉到该资源引用计数的裸指针。引用计数的内存必须动态分配。智能指针原创 2020-08-03 11:33:05 · 229 阅读 · 0 评论 -
Effective Modern C++ Item 18 使用std::unique_ptr管理具备专属所有权的资源
每当你需要使用智能指针时,std::unique_ptr基本上应是首选考虑。在默认的情况下,可以认为std::unique_ptr和裸指针有着相同的尺寸,并且对于大多数的操作,他们都是完全执行了相同的指令。也就是说,甚至可以在内存和时钟周期紧张的情况下使用std::unique_ptr。std::unique_ptr是一个只移型别。不可复制。实现的是一个专属所有权语义,一个非空的std::unique_ptr必定拥有其所指涉到的资源。std::unique_ptr只可移动,表示所有权从一个指针转移到另一个原创 2020-07-31 19:23:59 · 388 阅读 · 0 评论 -
Effective Modern C++ Item 17 理解特种成员函数的生成机制
在C++官方用于中,特种成员函数指的编译器会自动生成的成员函数。C++98中的规则C++98中提供了4种:默认构造函数、析构函数、复制构造函数、复制赋值运算符。生成条件:这些函数仅在需要时才会生成。通俗说来,某些代码中使用了它们,但是在类中并未显示声明的场合。生成特点:默认生成的都是public访问层级,并且是inline的,而且是非虚的。除非讨论的是一个析构函数,位于一个派生类中,并且基类的析构函数是个虚函数,在那种情况下,编译器为派生类生成的析构函数也是个虚函数,否则都是非虚的。C++11中的原创 2020-07-23 15:29:48 · 335 阅读 · 0 评论 -
Effective Modern C++ Item 16 保证const成员函数的线程安全性
业务场景:用一个类表示多项式,这个类中有一个接口可以输出多项式的根。那么代码会是像这样的:class Polynomial {public: using RootsType = std::vector<double>; ... RootsType roots() const; ...};一般来说,多项式值计算的代价高昂,我们不会每次都计算,当不得不计算的时候,我们会把算好的值缓存下来,然后遇到相同入参的时候,直接返回缓存值即可。那么大概是这样的实现:c原创 2020-07-23 10:27:29 · 281 阅读 · 0 评论 -
Effective Modern C++ Item 15 只要有可能使用constexpr,就使用它
C++11中引入的新词要评出一个“最令人困惑”大奖,那么constexpr很可能获此殊荣。当constexpr用于对象时,就是一个加强版本的const。当constexpr用于函数时,则是另外一种含义了。从字面上来说,constexpr表示的是既是const,又是编译阶段就已知。但实际上这个说法不全面,对于constexpr函数而言,它不产生const或者编译阶段就已知的结果。并且这种设计是有意为之,而且是个好事情。constexpr对象这些对象是真的具备const属性,并且是编译期就原创 2020-07-22 19:53:48 · 151 阅读 · 0 评论 -
Effective Modern C++ Item 14 只要函数不会发射异常,就为其加上noexcept声明
在C++98中,异常规格是一个喜怒无常的野兽。一般来说,不要招惹为好。而在C++11中,逐渐达成了一个共识:关于异常发射这个事情,关键在于是否会有异常,而不关注型别。所以当你知道这个函数不会发射异常,那么就应该给这个函数加上noexcept声明,否则这是一个接口规格缺陷。动机:让编译器更好的生成目标代码参考差异代码:int f(int x) throw(); //f不会发射异常:C++98风格int f(int x) noexcept; //f不会发射异常:C++11原创 2020-07-22 14:40:22 · 243 阅读 · 0 评论 -
Effective Modern C++ Item 13 优先选用const_iterator,而非interator
const_iterator是STL中相当于指涉到const的指针的等价物。它们指涉到不可以被修改的值。只要需要一个迭代器而其指涉内容没有修改必要,那么就应该用const_iterator但值得强调的是,在C++98中,const_iterator用起来困难重重,以下列举C++98中使用场景示例:// 对于以下调用,合理的应该改为const_iteratorstd::vector<int> values;...std::vector<int>::iterator it原创 2020-07-22 09:13:45 · 193 阅读 · 0 评论 -
Effective Modern C++ Item 12 为意在改写的函数添加override声明
C++ 中虚函数override动作,从而使得基类接口调用派生类函数成为了可能,而这个override动作工作起来,需要满足如下要求:基类中函数必须是虚函数。基类和派生类中的函数名字必须完全相同(析构函数除外)。基类和派生类中的函数形参型别必须完全相同。基类和派生类中的函数常量性必须完全相同。基类和派生类中的函数返回值和异常规格必须兼容。基类和派生类中的函数引用饰词必须完全相同。(C++11以后,含11要求)函数引用饰词这个语言特性以下做讲解:class Widg原创 2020-07-21 19:43:09 · 143 阅读 · 0 评论 -
Effective Modern C++ Item 11 优先选用删除函数,而非private未定义函数
有时候,你写了代码给其他程序员用,并且你想组织他们调用某个特定函数的话,你只需不要声明该函数即可。函数未经声明,不可调用,易如反掌。但是有些特定函数编译器会帮你生成,那么这个时候C++98里的一种常用处理方式是将其声明为私有函数,并且不去定义他们。例如如下代码:template<class charT, class traits = char_traits<charT> >class basic_ios : public ios_base {public:...privat原创 2020-07-20 20:37:01 · 252 阅读 · 0 评论 -
Effective Modern C++ Item 10 优先选用限定作用于的枚举型别,而非不限作用于的枚举型别
先来一个通用规则:如果在一对大括号里声明一个名字,则该名字的可见性救兵限定在括号括起来的作用域内。但这个规则有个例外 C++98风格的枚举型别不受此限制。这个例外导致一下代码会有错误:enum Color {black, white, red}; //black, white, red所在的作用域和Color相同auto white = false; //错误!white已经在范围内被声明过了优势1:不会造成命名污染这种枚举量名字泄露会带来很多弊原创 2020-07-20 19:51:51 · 190 阅读 · 0 评论 -
Effective Modern C++ Item 9 优先选用别名声明,而非typedef
先看个代码显示差别:优势1:容易理解// 常见用法差别,可能不明显typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;// 在涉及函数指针的时候,更容易理解typedef void (原创 2020-07-17 22:00:21 · 231 阅读 · 0 评论 -
Effective Modern C++ Item 8 优先选用nullptr,而非0或NULL
字面常量是0的型别是int,而非指针。而NULL的型别不确定,但不具有指针型别。这样的问题可以会出现在以下代码中:void f(int);void f(bool);void f(void*);f(0); //调用的是f(int),而不是f(void*)f(NULL); //可能通不过编译,一般也会调用f(int),从不会调用f(void*)f(nullptr); //调用的是f(void*)实际上,指导原则是不要在指针型别原创 2020-07-17 10:44:15 · 181 阅读 · 0 评论 -
Effective Modern C++ Item 7 在创建对象时注意区分()和{}
在C++11中,一个变量初始化的表达方式有太多种,如下所示:int x(0); //初始化值在小括号内int y = 0; //初始化值在等号后int z{0}; //初始化值在大括号内int z = {0}; //使用等号和大括号来指定初始化值,被视作只有大括号 //但由于有等号的存在,往往会让人误以为赋值了,实际没有。像int这样的内置类型,初始化和赋值只是学术之争,没太多区别。但原创 2020-07-16 21:49:13 · 175 阅读 · 0 评论 -
Effective Modern C++ Item 6 当auto推导的型别不符合要求时,使用带显示型别的初始化习惯用法
这里列举一个auto会出现推导错误的典型场景,代码如下:std::vector<bool> features(const Widget& w);Widget w;...bool highPriortiy = features(w)[5]; //w具有高优先级吗?...processWidget(w, highPriortiy); //按照w的优先级来处理之这上面的代码运行起来都很正常,但是将highPriortiy型别声明的时候换成auto,则后面原创 2020-07-15 19:22:31 · 193 阅读 · 0 评论 -
Effective Modern C++ Item 5 优先选用auto,而非显示型别声明
auto的优势可不仅仅是让你少打几个类型字符,在有些时候,可以防止手动指定型别带来的错误和性能问题。但这武器也有弊端,在没有IDE的时候,过度auto使用会影响代码的可读性,甚至在极端情况,会有一些意想不到的事情发生。优势1:auto语句定义变量在无初始化值的时候无法通过编译int x1; //有潜在的为初始化风险auto x2; //编译错误!必须要初始化auto x3 = 0; //没有问题,x的值有合适的定义优势2:auto表示可原创 2020-07-15 14:20:40 · 199 阅读 · 0 评论 -
Effective Modern C++ Item 4 掌握查看型别推导结果的方法
对于我们需要查看型别推导结果的时候,主要分为三个阶段:写代码阶段,编译阶段,运行时阶段。IDE编辑器IDE编辑器基本上都具有在鼠标悬停在变量或者auto 等字段上会自动推导类型的功能。如下代码所示:const int theAnswer = 42;auto x = theAnswer;auto y = &theAnswer;IDE编辑器会显示出,x的型别推导结果是int,y的是 const int &。编译器诊断信息一种另辟蹊径的方式,是故意诱发一个错误,然后让报错提示出型原创 2020-07-15 10:12:41 · 234 阅读 · 0 评论 -
Effective Modern C++ Item 3 理解decltype
先说说decltype这个关键词的常规运行方式const int i = 0; //decltype(i) 是 const intbool f(const Widget& w); //decltype(w) 是 const Widget&struct Point { int x, y; //decltype(Point::x)是int};原创 2020-07-14 22:49:15 · 247 阅读 · 0 评论