1. 从 C++11 开始,可以通过初始化表达式自动推导对象类型

2. 自动推导类型并不意味着弱化类型,对象还是强类型

3. 自动推导的几种常见形式

● auto: 最常用的形式,但会产生类型退化

类型退化:int& —>int const int& —> int

  1. //类型退化
  2. #include <iostream>
  3. #include <type_traits>
  4. int main()
  5. {
  6. int x = 3;
  7. int& ref = x;
  8. auto y = ref;
  9. std::cout << std::is_same_v<decltype(y),int> << std::endl;
  10. }

image.png

● const auto / constexpr auto: 推导出的是常量 / 常量表达式类型

程序会进行自动类型匹配,找到最符合的那个类型

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. auto x = 3;
  6. const auto y = 3;
  7. constexpr auto z = 3;
  8. std::cout << std::is_same_v<decltype(x),int> << std::endl;
  9. std::cout << std::is_same_v<decltype(y),const int> << std::endl;
  10. std::cout << std::is_same_v<decltype(z),const int> << std::endl;
  11. }

image.png

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. const int x = 3;
  6. const auto y = x; // const int --> int
  7. auto z = x;
  8. std::cout << std::is_same_v<decltype(y),const int> << std::endl;
  9. std::cout << std::is_same_v<decltype(z),int> << std::endl;
  10. }

image.png

● auto& : 推导出引用类型,避免类型退化

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. const int x = 3;
  6. auto& y = x;
  7. std::cout << std::is_same_v<decltype(y),const int&> << std::endl;
  8. const int& a = 3;
  9. auto& z = a;
  10. std::cout << std::is_same_v<decltype(z),const int&> << std::endl;
  11. }

image.png
再来看一下auto 和 auto& 的比较(以数组为例)

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x[3] = {1,2,3};
  6. auto x1 = x;
  7. std::cout << std::is_same_v<decltype(x1),int*> << std::endl;
  8. auto& x2 = x;
  9. std::cout << std::is_same_v<decltype(x2),int(&)[3]> << std::endl;
  10. }

image.png

● decltype(exp) :返回 exp 表达式的类型(左值加引用)

● decltype(val) :返回 val 的类型

decltype 和 auto 相比不会发生类型退化

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. int& y = x;
  7. auto y1 = y;
  8. decltype(y) y2 = y;
  9. std::cout << std::is_same_v<decltype(y1),int> << std::endl;
  10. std::cout << std::is_same_v<decltype(y2),int&> << std::endl;
  11. }

image.png
注意前面的auto&同样可以避免类型退化,但多了“引用”的额外负担;这里的y1的类型并不是const int,而是const int&。

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. const int y = x;
  7. auto& y1 = y;
  8. decltype(y) y2 = y;
  9. std::cout << std::is_same_v<decltype(y1),const int&> << std::endl;
  10. std::cout << std::is_same_v<decltype(y2),const int> << std::endl;
  11. }

image.png
左值加引用

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. int* ptr = &x;
  7. // ptr --> int*
  8. // *ptr --> int
  9. // 作为左值加引用 decltype(*ptr) --> int&
  10. std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
  11. }

image.png
矛盾的地方:这里的x 和 ptr 都是左值,但decltype(x)并不是int&类型,原因在于x是一个变量名称,而ptr可以视为一个表达式

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. int* ptr = &x;
  7. std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
  8. std::cout << std::is_same_v<decltype(x),int> << std::endl;
  9. }

image.png
进一步验证:

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. int* ptr = &x;
  7. std::cout << std::is_same_v<decltype(3.5 + 15l),double> << std::endl;
  8. std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
  9. std::cout << std::is_same_v<decltype(x),int> << std::endl;
  10. std::cout << std::is_same_v<decltype(ptr),int*> << std::endl; // ptr视为一个变量名称,尽管位于左值,但不加引用
  11. }

image.png
进一步扩展:

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. int x = 3;
  6. int* ptr = &x;
  7. std::cout << std::is_same_v<decltype(3.5 + 15l),double> << std::endl;
  8. std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
  9. std::cout << std::is_same_v<decltype(x),int> << std::endl;
  10. std::cout << std::is_same_v<decltype(ptr),int*> << std::endl;
  11. // 加()使之转化为一个表达式
  12. std::cout << std::is_same_v<decltype((x)),int&> << std::endl;
  13. }

image.png

● decltype(auto) :从 c++14 开始支持,简化 decltype 使用

  1. #include <iostream>
  2. int main()
  3. {
  4. decltype (3.5 + 15l) x = (3.5 + 15l);
  5. --->
  6. decltype (auto) x = (3.5 + 15l);
  7. }

● concept auto :从 C++20 开始支持,表示一系列类型( std::integral auto x = 3; )

增加一些限制:

  1. #include <iostream>
  2. #include <type_traits>
  3. int main()
  4. {
  5. std::integral auto x = 4; //限制在整数类型
  6. std::cout << std::is_same_v<decltype(x),int> << std::endl;
  7. }

image.png