C++ 类型推导(第二部分)
继续讨论 C++ 类型推导—— auto 类型推导。auto 变量定义过程中的类型推导可以分为两种:一种是花括号形式的初始化语句中auto类型推导、另一种是普通形式的初始化语句中auto类型推导。
如下代码片段展示了两种初始化形式,这两种形式将影响 auto 推导结果:
// c++98 中语法(普通形式)
int x = 88;
int y(88);// c++11 中统一初始化语法(花括号形式)
int x1 = {88};
int y1{88};
一、普通形式的初始化语句中auto类型推导
这种情况的 auto 类型推导可以与模板类型推导一一对应起来,这是因为函数模板中形参的形式和auto定义变量的形式是一致的。因此当用 auto 声明变量的时候 auto 对应到 T、变量的修饰词对应原来的函数参数形式(ParamType)。所以auto定义变量时类型推导结果同样取决于三种情况:
- 变量修饰词是指针或引用,但不是万能引用;
- 变量修饰词是万能引用;
- 变量修饰词既非指针也非引用;
目前只对第一、第三种情况举例,第二种情况到最后一部分讨论。
#define AUTO_VAL_TYPE_PRINT(_prefix, _v) do {\std::cout << _prefix##":" << \type_id_with_cvr<decltype(_v)>().pretty_name() << std::endl;\
} while(0)int main()
{// 等价 template<typename T> void test_value_pattern(T v)auto auto_v = 9;const auto auto_cv = auto_v;// 等价 template<typename T> void test_ref_pattern(T& v) auto &auto_ref = auto_v;// 等价 template<typename T> void test_const_ref_pattern(const T &v)const auto& auto_cref = auto_v;AUTO_VAL_TYPE_PRINT("auto_v", auto_v); AUTO_VAL_TYPE_PRINT("auto_cv", auto_cv);AUTO_VAL_TYPE_PRINT("auto_ref", auto_ref);AUTO_VAL_TYPE_PRINT("auto_cref", auto_cref);
}
auto 的推导结果对应模板参数T的推导结果,变量修饰词推导结果如下图所示:
二、花括号形式的初始化语句中auto类型推导
当使用大括号表达式初始化auto声明的变量时,推导出的变量类型一定是std::initializer_list的一个实例类型。所谓“std::initializer_list的一个实例类型”,是说std::initializer_list是一个泛化版本,类型推导时会根据元素的类型(假定为 type)生成特化版本std::initializer_list<type>。所以元素的类型必须一致。根据 visual studio 调试结果发现 y1 的结果并非我们所期,这是因为 C++17 中修改了推导规则(deepseek 提供,待考证)
int main()
{// class std::initializer_list<int>auto x1 = { 88 };// 取决于 c++ 版本auto y1{ 88 };AUTO_VAL_TYPE_PRINT("auto x1 = { 88 }", x1); AUTO_VAL_TYPE_PRINT("auto y1{ 88 }", y1);
}{88} 是一个 std::initializer_list<int> 类型的表达式。
在 C++11 中,auto 遇到 = { ... } 形式的初始化时,
会推导为 std::initializer_list<T>,其中 T 是花括号内元素的类型。这里 88 是 int,
所以:x1 的类型是 std::initializer_list<int>对于 auto y1{88}; C++11 也会推导为 std::initializer_list<int>(和 x1 一样)。C++17 规则有重要变化:
直接列表初始化 auto var{value} 或 auto var{value1, value2, ...} 的推导规则修改为:单元素:auto var{element} 推导为 T(不是 std::initializer_list<T>)多元素:auto var{a, b, ...} 非法(需要 = {a, b, ...} 才推导为 std::initializer_list)
三、C++14 中 auto 使用规则
C++14 中允许用auto替换函数返回值类型,用于表示推导返回值类型。因为这个推导是模板参数类型推导,所以不能用大括号构造返回值。
C++14 也允许在lambda表达式中用auto声明形参,这个推导是模板参数类型推导,所以不能用大括号构造实参。