参考翻译:https://cntransgroup.github.io/EffectiveModernCppChinese/Introduction.html
Item1:模板类型推导
template<typename T>
void f(ParaType param)
针对T的类型推导,取决于传递的实参类型,针对传入的ParaType有三种情况如下:
- 对于ParaType是通用引用,左值实参会被特殊对待
- 对于传值类型的推导,其const和volatile属性会被忽略
- 在模板类型推导中数组名和函数名会退化为指针,但可以修改模板形式,传递数组和函数的引用
Item2:理解auto类型推导
auto的类型推导机制与模板的机制几乎相同,除了在对使用花括号初始化的情况,比如auto x = {1}会将x推导为一个std::initializer_list<int>类型
Item3:理解decltype
在C++11中,decltype最主要的用途就是用于声明函数模板,而这个函数返回类型依赖于形参类型。举个例子,假定我们写一个函数,一个形参为容器,一个形参为索引值,这个函数支持使用方括号的方式(也就是使用“[]”)访问容器中指定索引值的数据,然后在返回索引操作的结果前执行认证用户操作。函数的返回类型应该和索引操作返回的类型相同。
template<typename Container, typename Index> //可以工作,
auto authAndAccess(Container& c, Index i) //但是需要改良
->decltype(c[i])
{
authenticateUser();
return c[i];
}
如果不适用decltype(c[i])进行类型说明,auto在推导c[i]的类型时会去掉其引用属性,函数将返回一个c[i]的拷贝而非引用
Item4:学会查看类型推导的结果
首先一些IDE工具可以帮助查看类型推导的结果,但并不总是正确
还可以使用编译器的错误报告查看,如下:
#include<vector>
template <typename T>
class TD; //声明了一个TypeDisplayer类但不定义
int main()
{
int x;
std::vector<int> y(10);
TD<decltype(x)> td1;
TD<decltype(y[0])> td2;
TD<decltype((x))> td3;
return 0;
}
使用编译器编译上述代码会出现其对类型的结果如图:
最后还有一些像自带的typeinfo和Boost的TypeIndex这样的库可以帮助在代码运行时输出类型信息,但它们不能保证绝对的正确
Item5,6:关于auto的使用
auto在针对函数对象的声明时可以更加方便且使用更少的内存进行存储,同时避免一些移植性和重构的问题,下面这个例子:
std::unordered_map<std::string, int> m;
…
for(const std::pair<std::string, int>& p : m)
{
… //用p做一些事
}
//使用auto的例子
for(const auto& p : m)
{
… //如之前一样
}
在第一个版本中没有使用auto去推导,而在unordered_map中的key是const的,所以正确的迭代形式应该是const std::pair<const std::string,int>&p : m但编译器会努力将上述代码转化为正确的代码,它会创建一个临时对象,并将这个临时对象的引用交给p,然后在一次循环结束时销毁这个临时对象,所以对p的取地址只是对临时对象取地址,而后面的auto可以推导出正确的类型,同时也更方便。
但在一些返回结果使用了代理类的类中使用auto可能会产生未定义的行为,比如有一个Matrix类,它将两个Matrix的+操作返回一个Sum的代理类(通常这样做是为了一些效率考虑,比如惰性求值等)
Matrix m1,m2,m3;
auto m4 = m1+m2+m3;
Matrix m5 = m1+m2+m3;
使用auto推导的m4类型可能就是一个Sum<Sum<Matrix,Matrix>,Matrix>类,当然这些代理类通常会提供转换为结果的方法,但如果不了解其返回类型的设计直接使用auto就可能产生一些与直觉相背的行为,如果发现有这样的情况可以通过改造auto语句解决比如auto m4 = static<Matrix>(m1+m2+m3);
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2128099421@qq.com