1_auto类型推导(深入应用C++11:代码优化与工程级应用)
1. auto回顾
在深入学习auto前,本人已经了解了auto的基本用法,对于简单类型推导能够清晰理解.如:
int i = 0;
auto ii = 1; // auto被推导为int
auto iii = i; // auto被推导为int
本次学习是为了加深细节理解,如:auto 与指针\引用\cv限定符一起使用时的推导结果.
回顾下简单类型的推导及使用auto时需要注意哪些.
int int_type = 1; //int auto被推导为int
float float_type = 1.0; //float auto被推导为float
const int const_int_type = 1; //int const auto被推导为int
auto auto_int = 1; //int auto被推导为int
auto auto_double = 1.0; //double auto被推导为double
auto x= 5; //int auto被推导为int
auto pi = new auto(1); //int* auto被推导为int*
const auto *v = &x, u=6; //v:int const * auto 被推导为 int
//u:int const auto 被推导为 int
static auto y = 0.0; //double auto被推导为double
auto int r; // error:two or more data types in declaration of 'r'
int int r; // error:two or more data types in declaration of 'r'
auto s; // error:declaration of 'auto s' has no initializer
需要注意的是:
const auto *v = &x, u=6;
//在推导的时候u必须赋值,且所赋的值不能让auto推导产生二义性,否则无法通过编译
/**u 必须要赋值,否则就等价 const auto u;// error
* 如:const auto *v = &x, u;
* error: declaration of variable 'u' with deduced type 'const auto' requires an initializer
*/
/**并且u的初始化不能是编译器推导产生二义性,否则编译失败.
* 如:const auto *v = &x, u =6.0;
* error: 'auto' deduced as 'int' in declaration of 'v' and deduced as 'double' in declaration of 'u'
*/
由上面的例子可以看出来,auto并不能代表一个实际的类型声明(如s的编译错误),只是一个类型声明的"占位符".
使用auto声明的变量必须马上初始化,以上编译器推断出它的实际类型,并在编译时将auto占位符替换为真正的类型.
2. auto推导规则
int x = 0;
auto * a = &x; // int* auto被推导为int
auto b = &x; // int* auto被推导为int*
auto & c = x; // int& auto被推导为int
auto d = c; // int auto被推导为int
const auto e = x; // int const auto被推导为int
auto f = e; // int auto被推导为int
const auto & g = x; // int const & auto被推导为int
auto & h = g; // int const & auto被推导为int const
const auto * gg = &x; // int const * auto被推导为int
auto * hh = gg; // int const * auto被推导为int const
由上面的例子可以看出:
- a和c的推导结果是很显然的, auto在编译的时候被替换为int, 因此a和c分别被推导为int*和int&.
- b的推导结果说明, 其实auto不声明为指针, 也可以推导出指针类型.
- d的推导结果说明, 当表达式是一个引用类型时, auto会把引用类型抛弃, 直接推导成原始类型int.
- e的推导结果说明, 当表达式带有const(实际上volatile也会得到同样的结果)属性时, auto会把const属性抛弃掉, 推导成non-const类型int.
- g/h的推导说明, 当auto和引用(换成指针在这里也将得到同样的结果, 如:用gg推导hh)结合时, auto的推导将保留表达式的const属性.
通过上面一系列示例, 可以得到下面两条规则:
- 当不声明为指针或引用时, auto的推导结果和初始化表达式抛弃引用和cv限定符后类型一致.
- 当声明为指针或引用时, auto的推导结果将保持初始化表达式的cv属性.
3. auto与函数模板
auto的推导和函数模板参数的自动推导有相似之处.下面模板参数的自动推导和auto的类型是一致的:
template<typename T> void func(T x){}
template<typename T> void func(T * x){}
template<typename T> void func(T & x){}
template<typename T> void c_func(const T x){}
template<typename T> void c_func(const T * x){}
template<typename T> void c_func(const T & x){}
func(x); // func(T x) 参数被推导为int T被推导为int
func(&x); // func(T * x) 参数被推导为int* T被推导为int
func(x); // func(T & x) 参数被推导为in& T被推导为int
func(e); // func(T x) 参数被推导为int T被推导为int
func(gg); // func(T * x) 参数被推导为int const * T被推导为int const
func(h); // func(T & x) 参数被推导为int const & T被推导为int const
c_func(e); // c_func(const T x) 参数被推导为int const T被推导为int
c_func(gg); // c_func(const T * x) 参数被推导为int const * T被推导为int
c_func(h); // c_func(const T & x) 参数被推导为int const & T被推导为int
注意:(T x)版本的模板和(T & x)的模板在验证时只能使其中一个版本生效, 否则会使推导产生二义性导致无法编译. (const T x)与(const T & x)也是如此.
auto不能用作函数的参数. 这点很容易理解, 如果auto可以用作函数的参数, 相当于在编译时就需要对该函数定义所有可能参数的类型.
void func_auto(auto a){ // error: 'auto' not allowed in function prototype
}
// 相当于需要定义一下函数
void func_auto(char a){}
void func_auto(unsigned char a){}
void func_auto(short a){}
void func_auto(unsigned short a){}
void func_auto(int a){}
void func_auto(unsigned int a){}
void func_auto(float a){}
void func_auto(unsigned float a){}
void func_auto(double a){}
void func_auto(unsigned double a){}
void func_auto(long a){}
void func_auto(unsigned long a){}
void func_auto(long long a){}
void func_auto(unsigned long long a){}
...
...
...
4. auto的限制
上一小节结尾已经梳理了auto不可以作为函数参数的自动推导.那还有哪些情况下无法使用auto自动推导呢?
auto func_ra(){ // error: 'auto' return without trailing return type; deduced return types are a C++14 extension
return 0;
}
auto func_ra(int a,int b)->decltype (a+b){ // OK
return a+b;
}
class A {
public:
auto a =0; // error: 'auto' not allowed in non-static class member
static const auto ai2 = 0;
// static const auto af2 = 0.0; // error: in-class initializer for static data member of type 'const double' requires 'constexpr' specifier
static int x; // static const 的整形或者枚举成员才可以在类内初始化.
// 否则就只能在类内声明,在类外通过A::的形式初始化
static int y = 0; // error: non-const static data member must be initialized out of line
static double d = 0.0; // error: non-const static data member must be initialized out of line
static float f = 0.0; // error: non-const static data member must be initialized out of line
static char c = '0'; // error: non-const static data member must be initialized out of line
static const int c_i = 0;
static const double c_d = 0.0; // error: in-class initializer for static data member of type 'const float' requires 'constexpr' specifier note: add 'constexpr'
static const float c_f = 0.0; // error: in-class initializer for static data member of type 'const float' requires 'constexpr' specifier note: add 'constexpr'
static const char c_c = '0';
};
int A::x = 0;
template <typename T>
class B{};
int array[4] = {0};
auto aarray = a;
auto array2[4] = array; // error: 'array2' declared as array of 'auto'
auto array3[4] = {0}; // error: 'array3' declared as array of 'auto'
B<int> bb;
B<auto> a_bb = bb; // error: 'auto' not allowed in template argument
通过测试可以得到一下规则:
- auto只能static const 整形或者枚举 成员
- auto无法作为模板的参数类型传入
- auto无法推导数组的类型
- auto无法直接作为函数的返回值进行自动推导(在c++14后是可以的,c++11不允许), 但是可以和decltype结合使用.
- auto无法直接作为模板函数的返回值使用, 但是可以和decltype结合使用. 后面介绍decltype时会具体验证.
分类:
读一本书系列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)