#include <iostream>
#include <vector>
#include <typeinfo>
#include <list>
/*
1.当不声明为指针或引用时,auto的推导结果和初始化表达式
抛弃引用和cv(const、volatile)限定符后类型一致;
2.当声明为指针或引用时,auto的推导结果将保持初始化表达式的csv属性;
3.不能用于函数的参数,必须被初始化,C++20可以了
4.不能用于非静态成员变量,非静态成员属于对象,对象创建的时候才会对非静态成员初始化,auto编译阶段进行类型推导,非静态成员变量编译时变量还没有进行初始化
5.不能使用auto定义数组和赋值
int arr[] = {1,2,3};//ok
auto arr1[]={1,2,3}; //error
auto arr2[]=arr; // error
auto arr3 = arr; // ok ,arr3=>int*
6.一般用于iterator迭代器类型声明
7.定义一个泛型函数func,多个类中都有
get()静态返回值函数,但返回类型不同,若想在
func中调用get函数并获取其返回值,需要使用auto进行
变量类型声明;
8.类的静态非常量成员变量也不可以修饰,static auto var1=0; //error
类的静态常量成员变量可以被auto修饰, static const auto var1=0;//ok, const变量被初始化,可以正常推导
9.无法使用auto推导模板类型
template<typename T>
struct Test{};
Test<int> t;
Test<auto> t1 = t; //error,auto不能推出模板类型
*/
void test1()
{
std::vector<int> vec = {1, 2, 3, 4, 5};
// 若不使用auto类型推导,则会写很长的冗余std::vector<int>::iterator
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
std::cout << *it << std::endl;
}
// 使用auto优化代码变得更简洁
for (auto it = vec.begin(); it != vec.end(); ++it)
{
std::cout << *it << std::endl;
}
}
// 1.当不声明为指针或引用时,auto的推导结果和初始化表达式
// 抛弃引用和cv(const、volatile)限定符后类型一致;
// 2.当声明为指针或引用时,auto的推导结果将保持初始化表达式的csv属性;
void test2()
{
int x = 0;
const auto e = x; // e->const int
auto f = e; // f->int,原因:当表达式带有const属性时,auto会把const属性抛弃掉,推导成non-const类型int;
const auto &g = x;
std::cout << typeid(g).name() << std::endl; // g->const int
auto &h = g; //推导出h->const int&,当auto和引用结合时auto的推导将保留表达式的const属性;
}
// 在宏定义中应用,场景性能会提升
#define MAX1(a, b) (a) > (b) ? (a) : (b)
#define MAX2(a, b) \
{ \
auto _a = (a); \
auto _b = (b); \
_a > _b ? (_a) : (_b); \
}
void test3()
{
MAX1(1 + 2 + 3, 2 + 3 + 4); // a或b其中一个会经过两次计算
MAX2(1 + 2 + 3, 2 + 3 + 4); // MAX2使用auto推导出结果进行比较,性能优
}
// auto声明的指针或引用变量不能指向或绑定一个临时对象
int Temp() { return 0; }
void test4()
{
// auto *p = &Temp(); // error
// auto &l = Temp(); // non-const引用不能指向一个临时变量
auto &&r = Temp(); // 右值引用指向临时变量完全没问题,临时变量声明周期与r进行绑定
}
// auto与其他类型一样,可以一行定义多个变量(只有第一个类型被推导,推导出的数据类型用于其他变量),所以
// 不允许这些变量类型不相同,如果类型不相同编译报错,但不建议一行定义多个变量
void test4()
{
auto a = 0, b = 1; // a and b all int
// auto c = 1, d = 2.0f; // error
}
// auto不适用于数组定义和赋值
void test3()
{
int array[] = {1, 2, 3, 4, 5};
// auto array[] = {1, 2, 3, 4, 4, 5}; // error, auto不能定义数组
// auto array1[] = array; // error, auto不能用于数组赋值
}
// 不能用于函数参数和模板参数
void function(auto it)
{
std::cout << it << std::endl;
}
template <typename T>
struct Test
{
// auto不能用于类的静态非常量数据成员,静态const成员可以
// static auto it; // error
static const auto cit = 0;//ok,const 常量被初始化,可以正常推导
};
void test4()
{
function(1);
function("c++"); // c++20可以
Test<int> t;
// Test<auto> it = t; error, can not referred
// 不能用于
}
// auto适用于泛型函数
struct A
{
static int Do()
{
std::cout << "class A" << std::endl;
return 0;
}
};
struct B
{
static std::string Do()
{
std::cout << "class B" << std::endl;
return std::string("B");
}
};
template <typename T>
void func()
{
auto res = T::Do(); // auto虽然不能作为模板参数推导类型,但可以用于模板函数中变量声明
std::cout << res << std::endl;
}
void test5()
{
func<A>();
func<B>();
}
// 若不使用auto关键字,但模板函数需要另一个参数用于指定返回值
template <typename T, typename R>
void funcNew()
{
R res = T::Do();
std::cout << res << std::endl;
}
void test6()
{
funcNew<A, int>();
funcNew<B, std::string>();
}
// auto 可以用于函数返回值类型推导(尾返回类型推导)
template<typename T1, typename T2, typename R>
R add1(T1 t1, T2 t2) {
return t1+t2;
}
// 发现函数调用还要传递返回值类型,但有的情况不知道返回值类型就需要使用auto
// 但可能会想到使用decltype,但编译报错,从左到右编译时发现t1和t2尚未定义,因此c++11引入
// 尾返回类型
template<typename T1, typename T2>
decltype(t1+t2) add2(T1 t1, T2 t2) {
return t1+t2;
}
// 尾返回类型decltype(t1+t2),结合auto一起使用(c++14可以去掉尾返回类型decltype)
template<typename T1, typename T2>
auto add2(T1 t1, T2 t2)->decltype(t1+t2) {
return t1+t2;
}
// decltype(auto):用于对转发函数或封装的返回类型进行推导
std::string lookup1();
std::string& lookup2();
std::string lookup_str() {
return lookup1();
}
std::string& lookup_str_ref() {
return lookup2();
}
decltype(auto) lookup_str1() {
return lookup1();
}
decltype(auto) lookup_str_ref1() {
return lookup2();
}
C++ 新特性auto
于 2021-09-11 23:05:47 首次发布