1. auto
1.1 auto的使用场景
(1)优化map的查找
std::map<std::string, int> NewMap = {
{"one", 1}, {"two", 2}, {"three", 3}
};
// C++17可支持,使用auto遍历map
for (auto [key, val] : NewMap)
{
std::cout << val << std::endl;
}
(2)结构体/类的拆解
class MyStruct
{
public:
int id;
std::string name;
};
int main()
{
MyStruct TestStruct(1, "Hello");
// 用auto对类或者结构体里面的变量进行性拆解
auto [x, y] = TestStruct;
std::cout << x << " , " << y << std::endl;
}
(3)使用类似于泛型编程的作用
针对于函数返回值
/**
* auto:函数返回值推导
* 注意:返回值类型一定要一致否则无法推导
*/
auto sum(long x, long y)
{
return x + y;
}
针对于lambda表达式
/**
* auto:lambda表达式完全泛型
*/
auto l1 = [](auto x, auto y)
{
return x + y;
};
// lambda返回值引用的方法
auto l2 = [](int& i) -> auto&
{
return i;
};
针对于非类型模板
/**
* auto:非类型模板的auto类型自动推导
* 注意:auto无法推导double类型,因为double会损失精度
*/
template<auto N>
void f()
{
std::cout << N << std::endl;
}
int main()
{
f<5>();
f<'x'>;
f<5.0>; // 错误,用auto作为模板类型推导不能使用double
}
(4)万能引用
int i =10;
auto&& x = i; // i为左值,auto推导为int&,即x为左值引用int&
auto&& y = 10; // 10为右值,auto推导为int,即y为右值引用int&&
1.2 理论部分
auto的注意事项:
(1)auto会推导类型,但引用不是类型,因此会忽略引用。
(2)auto会忽略值类型的const,而保留修饰指向对象的const,即会保留指针的const;如果需要const,使用auto&即会保留原有值对应的const;也可以使用const auto。
(3)auto不会影响编译速度,甚至会加快编译速度。
2. typeid
2.1 使用场景
int x = 0;
std::cout << typeid(x).name() << std::endl;
2.2 理论部分
typeid的注意事项:
(1)typeid返回值的type_info中的name所返回类型名在C++中没有明确的规定,不同版本输出会不一样。
(2)typeid的返回值std::type_info是一个左值,其生命周期一直到程序生命周期结束。
(3)std::type_info删除了复制构造函数,若想保存std::type_info需要引用或指针。
(4)typeid会忽略const,也就是typeid(const T) == typeid(T)。
3. decltype
3.1 decltype使用场景
(1)优化函数模板的返回类型
/**
* 使用decltype对返回值类型进行限定
* 在C++14后auto已经能自动推导,并不需要 -> decltype,但auto返回值类型而不返回引用
*/
template<class T1, class T2>
auto sun(T1 x, T2 y) -> decltype(x + y)
{
return x + y;
}
/** 若想返回引用就一定要使用decltype */
template<class T>
auto sun(T& x) -> decltype(x)
{
return x;
}
(2)模板前置返回值的推导类型
/** 使用static_cast进行强制转化 */
template<class T1, class T2>
decltype(*static_cast<T1*>(nullptr) + *static_cast<T2*>(nullptr)) sum1(T1 t1, T2 t2)
{
return t1 + t2;
}
/** 使用std::declval进行类型对象的获取 */
template<class T1, class T2>
decltype(std::declval<T1> + std::declval<T2>) sum2(T1 t1, T2 t2)
{
return t1 + t2;
}
decltype(auto):在使用上完全和auto一致,只是用decltype的推导规则。同时注意decltype(auto)只能单独声明,不能结合指针、引用或者cv限定。
/** 使用decltype(auto),优化返回引用 */
template<class T>
decltype(auto) sun(T& x)
{
return x;
}
/** 使用decltype(auto),优化非类型模板的auto类型自动推导 */
template<decltype(auto) N>
void f()
{
std::cout << N << std::endl;
}
3.2 理论部分
decltype在使用上与typeof()完全一致,decltype极大的加强了C++的泛型能力。
注意:使用decltype推导表达式,主要看表达式本身返回一个左值引用还是值类型。
struct MyStruct
{
double x;
};
int main()
{
const MyStruct* TestStruct = new MyStruct();
int i;
int* j;
int a[10];
decltype(i); // 推导表达式的类型,为int
decltype((TestStruct->x)); // 推导()表达式的类型,应该是一个引用,类型为const double&
decltype(i = 0); // 推导表达式的类型,为int&
decltype(0, i); // 推导逗号表达式,为int&
decltype(i, 0); // 推导逗号表达式,为int
decltype(i++); // 返回亡值,推导类型为int
decltype(++i); // 推导类型为int&
decltype(*j); // 推导类型为int&
decltype(a[5]); // 推导类型为int&
};
遵从以下规则:
(1)当表达式的值类别为亡值,会返回T&&;
(2)当表达式的值类别是左值,且该实参是没有括号的标识表达式,则会返回该实参的类型即T;
(3)当表达式的值类别是左值,且该实参不是是没有括号的标识表达式,则会返回T&;
(4)当表达式的值类别是纯右值,会返回T。