最近有小伙伴说没有收到当天的文章推送,这是因为微信改了推送机制,有一部分小伙伴刷不到当天的文章,一些比较实用的知识和信息,错过了就是错过了,建议大家加个星标⭐️,就能第一时间收到推送
虽然《Effective C++》系列已讲了足够多的知识点,我都多少有些头昏脑胀了,但很可惜C++入门之旅仍然没有结束。
C++11/14标准堪称脱胎换骨,有必要先读完这本《Effective Modern C++》,学习11/14的新特性和习惯做法,而后再阅读源码或上手自己的项目。
条款1、理解模板类型推导
考虑这种形式,T为模板参数,ParamType为形参,expr为实参:
template<typename T>
void f(ParamType param);
f(expr);
在模板类型推导时,实参的引用性会被忽略;若形参还是按值传递时(T),实参的const、volatile也会被忽略。
template<typename T>
void f(T& param);
int x = 27;
const int cx = x;
const int &rx = x;
// T为int,形参为int&
f(x);
// T为const int,形参为const int&
f(cx);
// 忽略rx的引用性,T为const int,形参为const int&
f(rx);
而形参是万能引用时,若实参是右值,情况与上面相同;若实参是左值,情况发生变化,T和形参都被推导为左值引用。至于什么是万能引用、左值右值,后续会讲。
模板类型推导过程中,数组或函数型别的实参会退化成对应指针,除非形参是引用(T&)。
条款2、理解auto类型推导
auto类型推导基本上和模板类型推导一样。
const auto& rx = x;
//rx的类型推导类似下面param
template
void f(const T& param);
唯一例外在于auto会假定大括号初始化表达式代表一个std::initializer_list,而模板类型推导无法处理。
// x是std::initializer_list
auto x = { 11, 23, 9 };
// 无法编译
template<typename T>
void f(T param);
f({ 11, 23, 9})
此外,C++14中在函数返回值或lambda的形参中的auto使用的是模板类型推导。
条款3、理解decltype
绝大多数情况下,不同于模板与auto,decltype会得出变量或表达式的类型而不作任何更改。
bool f(const Widget& w);
decltype(w)是const Widget&
decltype(f)是bool(const Widget&)
decltype(f(w))是bool
C++14支持decltype(auto),它像auto一样自动推导类型,但用的是decltype的规则,可以用于函数返回值或变量声明。
//C++11支持返回值型别尾序语法
//返回auto时需要将返回值类型置于形参列表后
template
auto At(Container& c, Index i) -> decltype(c[i]){
return c[i];
}
//C++14返回值只需auto即可,但类型推导规则可能出错
//例如下面auto推导时去除了c[i]的引用性,无法给c[i]赋值
template
auto At(Container& c, Index i) {
return c[i];
}
//采用decltype(auto)即可
template
decltype(auto) At(Container& c, Index i) {
return c[i];
}
//考虑左值右值,需要用万能引用和forward
//具体后文再讲
template
decltype(auto) At(Container&& c, Index i){
return std::forward
(c)[i]; }
decltype推导规则的例外是对于比仅有名字更复杂的左值表达式(名字是左值表达式),decltype得出的类型总是左值引用。
decltype(auto) Func(){
int x = 0;
//只有名字,返回int
return x;
//比名字更复杂,返回int&
return (x);
}
条款4、掌握查看类型推导结果的方法
利用IDE编辑器、编译器错误消息和Boost.TypeIndex库常常能够查看到推导而得的类型。
但有时结果可能无用或不准确,因此有必要理解C++类型推导规则。
条款5、优先选用auto,而非显式类型声明
auto变量必须初始化,不仅仅可以比显式指定类型少打字,还可以避免类型不匹配时不想要也没想到的隐式类型转换。
std::unordered_map<std::string, int> m;
//p的类型应该是std::pair
//导致拷贝了一系列临时对象,不仅增加了成本,还无法取得p真正地址
for (const std::pair<std::string, int> &p : m)
//没有上述问题
for (const auto &p : m)
条款2和条款6描述了auto的缺点。
条款6、当auto推导的类型不符合要求时,使用显式类型
隐形的代理类型可以导致auto根据初始化表达式推导出不符合预期的类型。
例如正常的std::vector::operator[]返回元素的引用,但对于bool来说由于C++禁止比特的引用,所以std::vector
vector<bool> vec(10);
//隐式转换成bool,类型正确
bool flag = vec[0];
//flag类型是std::vector
::reference auto flag = vec[0];
近期发现了一份 20T各类编程/影视/学习资源的腾讯文档,其中除了互联网编程学习资源外,还有不少影视资源,分享给各位:
资源链接:https://docs.qq.com/sheet/DY3VPVklVaFFMcUZ4?tab=9h5afr (右键复制到浏览器地址栏打开),或者点击文末「阅读原文」也可查看。
欢迎你添加我的微信,我拉你进技术交流群。此外,我也会经常在微信上分享一些好用工具、白嫖福利、各类资源以及工作体验,还有一些内推机会。
加个微信,打开另一扇窗