1. 从 C++11 开始,可以通过初始化表达式自动推导对象类型
2. 自动推导类型并不意味着弱化类型,对象还是强类型
3. 自动推导的几种常见形式
● auto: 最常用的形式,但会产生类型退化
类型退化:int& —>int const int& —> int
//类型退化
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int& ref = x;
auto y = ref;
std::cout << std::is_same_v<decltype(y),int> << std::endl;
}
● const auto / constexpr auto: 推导出的是常量 / 常量表达式类型
程序会进行自动类型匹配,找到最符合的那个类型
#include <iostream>
#include <type_traits>
int main()
{
auto x = 3;
const auto y = 3;
constexpr auto z = 3;
std::cout << std::is_same_v<decltype(x),int> << std::endl;
std::cout << std::is_same_v<decltype(y),const int> << std::endl;
std::cout << std::is_same_v<decltype(z),const int> << std::endl;
}
#include <iostream>
#include <type_traits>
int main()
{
const int x = 3;
const auto y = x; // const int --> int
auto z = x;
std::cout << std::is_same_v<decltype(y),const int> << std::endl;
std::cout << std::is_same_v<decltype(z),int> << std::endl;
}
● auto& : 推导出引用类型,避免类型退化
#include <iostream>
#include <type_traits>
int main()
{
const int x = 3;
auto& y = x;
std::cout << std::is_same_v<decltype(y),const int&> << std::endl;
const int& a = 3;
auto& z = a;
std::cout << std::is_same_v<decltype(z),const int&> << std::endl;
}
再来看一下auto 和 auto& 的比较(以数组为例)
#include <iostream>
#include <type_traits>
int main()
{
int x[3] = {1,2,3};
auto x1 = x;
std::cout << std::is_same_v<decltype(x1),int*> << std::endl;
auto& x2 = x;
std::cout << std::is_same_v<decltype(x2),int(&)[3]> << std::endl;
}
● decltype(exp) :返回 exp 表达式的类型(左值加引用)
● decltype(val) :返回 val 的类型
decltype 和 auto 相比不会发生类型退化
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int& y = x;
auto y1 = y;
decltype(y) y2 = y;
std::cout << std::is_same_v<decltype(y1),int> << std::endl;
std::cout << std::is_same_v<decltype(y2),int&> << std::endl;
}
注意前面的auto&同样可以避免类型退化,但多了“引用”的额外负担;这里的y1的类型并不是const int,而是const int&。
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
const int y = x;
auto& y1 = y;
decltype(y) y2 = y;
std::cout << std::is_same_v<decltype(y1),const int&> << std::endl;
std::cout << std::is_same_v<decltype(y2),const int> << std::endl;
}
左值加引用
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int* ptr = &x;
// ptr --> int*
// *ptr --> int
// 作为左值加引用 decltype(*ptr) --> int&
std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
}
矛盾的地方:这里的x 和 ptr 都是左值,但decltype(x)并不是int&类型,原因在于x是一个变量名称,而ptr可以视为一个表达式
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int* ptr = &x;
std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
std::cout << std::is_same_v<decltype(x),int> << std::endl;
}
进一步验证:
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int* ptr = &x;
std::cout << std::is_same_v<decltype(3.5 + 15l),double> << std::endl;
std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
std::cout << std::is_same_v<decltype(x),int> << std::endl;
std::cout << std::is_same_v<decltype(ptr),int*> << std::endl; // ptr视为一个变量名称,尽管位于左值,但不加引用
}
进一步扩展:
#include <iostream>
#include <type_traits>
int main()
{
int x = 3;
int* ptr = &x;
std::cout << std::is_same_v<decltype(3.5 + 15l),double> << std::endl;
std::cout << std::is_same_v<decltype(*ptr),int&> << std::endl;
std::cout << std::is_same_v<decltype(x),int> << std::endl;
std::cout << std::is_same_v<decltype(ptr),int*> << std::endl;
// 加()使之转化为一个表达式
std::cout << std::is_same_v<decltype((x)),int&> << std::endl;
}
● decltype(auto) :从 c++14 开始支持,简化 decltype 使用
#include <iostream>
int main()
{
decltype (3.5 + 15l) x = (3.5 + 15l);
--->
decltype (auto) x = (3.5 + 15l);
}
● concept auto :从 C++20 开始支持,表示一系列类型( std::integral auto x = 3; )
增加一些限制:
#include <iostream>
#include <type_traits>
int main()
{
std::integral auto x = 4; //限制在整数类型
std::cout << std::is_same_v<decltype(x),int> << std::endl;
}