Effective Modern C++

  1. Item1:模板类型推导
  2. Item2:理解auto类型推导
  3. Item3:理解decltype
  4. Item4:学会查看类型推导的结果
  5. Item5,6:关于auto的使用

参考翻译: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

×

喜欢就点赞,疼爱就打赏