
一、auto和decltype的用法和区别
1、auto关键字 (c++11 引入)
auto 是一个用于自动类型推导的关键字。它主要用于变量声明,让编译器根据变量的初始化表达式来推导出变量的类型。
1.1、基本用法
auto x = 42; // x 的类型被推导为 int auto y = 3.14; // y 的类型被推导为 double auto str = "hello"; // str 的类型被推导为 const char*
1.2、优势
- 简化代码: 特别适用于类型名称冗长复杂的情况(如迭代器、lambda 表达式)。
std::vector<std::map<std::string, int>> complexvector;
// 不用写复杂的迭代器类型
for (auto it = complexvector.begin(); it != complexvector.end(); ++it) {
// ...
}
- 提高可维护性: 如果初始化表达式的类型改变(例如函数返回类型改变),使用
auto的变量类型会自动随之改变,无需修改多处代码。 - 通用性: 在模板编程中,有时无法预先知道具体类型,
auto可以用于推导依赖模板参数的类型。
template <typename t, typename u>
auto add(t t, u u) -> decltype(t + u) { // 函数返回类型也可以用 auto + 尾置返回类型 (c++11)
return t + u;
}
1.3、 注意事项
- 必须初始化:
auto变量必须在声明时初始化,否则编译器无法推导类型。 - 引用和常量性:
auto会忽略初始化表达式的引用和顶层const(指对象本身是const)。
int i = 10; const int ci = 20; int& ref_i = i; const int& cref_i = ci; auto a = ci; // a 是 int (顶层 const 被忽略) auto b = ref_i; // b 是 int (引用被忽略) auto c = cref_i; // c 是 int (引用和顶层 const 被忽略) a = 30; // 合法 b = 40; // 合法 // 如果需要保留引用或 const,需要显式加上 auto& d = ref_i; // d 是 int& const auto e = ci; // e 是 const int
数组和函数指针: auto 推导数组类型会得到指针类型,推导函数类型也会得到函数指针类型。
int arr[5] = {1, 2, 3, 4, 5};
auto p = arr; // p 的类型是 int*
void func();
auto pf = func; // pf 的类型是 void (*)()1.4、 auto 的高级用法
auto 除了可以独立使用,还可以和某些具体类型混合使用,这样 auto 表示的就是“半个”类型,而不是完整的类型。请看下面的代码:
int x = 0; auto *p1 = &x; //p1 为 int *,auto 推导为 int auto p2 = &x; //p2 为 int*,auto 推导为 int* auto &r1 = x; //r1 为 int&,auto 推导为 int auto r2 = r1; //r2 为 int,auto 推导为 int
auto和const结合:
int x = 0; const auto n = x; //n 为 const int ,auto 被推导为 int auto f = n; //f 为 const int,auto 被推导为 int(const 属性被抛弃) const auto &r1 = x; //r1 为 const int& 类型,auto 被推导为 int auto &r2 = r1; //r1 为 const int& 类型,auto 被推导为 const int 类型`在这里插入代码片`
1.4、 auto 的限制
- auto 不能在函数的参数中使用
- auto 不能作用于类的非静态成员变量(也就是没有 static 关键字修饰的成员变量)中。
- auto 关键字不能定义数组,比如下面的例子就是错误的:
char url[] = “http://c.biancheng.net/”; auto str[] = url; //arr 为数组,所以不能使用 auto
- 多个变量声明时类型必须一致。
- auto 不能作用于模板参数,请看下面的例子:
template <typename t>
class a{
//todo:
};
int main(){
a<int> c1;
a<auto> c2 = c1; //错误
return 0;
}2、decltype关键字 (c++11 引入)
decltype 用于查询表达式的类型。它不会计算表达式的值,只是分析表达式并返回其类型。
2.1、基本用法
int i = 42; decltype(i) di; // di 的类型是 int double d = 3.14; decltype(d) dd = d; // dd 的类型是 double
2.2、核心规则
decltype的行为取决于传递给它的表达式:- 表达式是未加括号的变量 (如
decltype(x)):
int i = 0; int& ref_i = i; const int ci = 1; const int& cref_i = ci; decltype(ref_i) dr = i; // dr 是 int& decltype(ci) dc = 2; // dc 是 const int decltype(cref_i) dcr = ci; // dcr 是 const int&
返回该变量的声明类型,包括其引用和顶层 const。
表达式是加括号的变量 (如 decltype((x))):
int i = 0; decltype((i)) di = i; // di 是 int& decltype((5)) d5 = 5; // d5 是 int&& (5 是右值)
- 返回该变量的引用类型。如果变量本身是左值,则返回左值引用 (
t&),如果变量是右值,则返回右值引用 (t&&)。这是一种特殊情况。 - 表达式是其他类型(函数调用、运算符表达式等):
int i = 0; int* p = &i; decltype(*p) d = i; // *p 是左值表达式,d 是 int& decltype(i + 1) di = i; // i+1 是右值表达式,di 是 int decltype(++i) di_inc = i; // ++i 是左值表达式 (返回 i 的引用),di_inc 是 int& decltype(i++) di_post; // i++ 是右值表达式 (返回旧值的副本),di_post 是 int
- 返回该表达式计算结果对应的类型。如果表达式产生左值,则返回左值引用 (
t&),如果产生右值,则返回非引用类型 (t)。这与decltype((x))类似。
2.3、优势与用途
- 精确获取类型: 保留表达式的完整类型信息,包括引用和
const限定符。这是它与auto的关键区别。 - 函数返回类型推导 (c++11): 结合尾置返回类型语法,用于推导依赖模板参数的复杂返回类型。
template <typename t, typename u>
auto add(t t, u u) -> decltype(t + u) { // 推导返回类型
return t + u;
}
- 元编程: 在模板元编程中,需要精确知道某个表达式或类型的特性时非常有用。
- lambda 表达式类型: 虽然 lambda 表达式类型是唯一的且未命名,但可以用
decltype获取其类型(虽然通常更常用auto或std::function)。
auto lambda = []{ return 42; };
decltype(lambda) anotherlambda = lambda; // anotherlambda 是同类型 lambda
3、auto和decltype的区别总结
| 特性 | auto | decltype |
|---|---|---|
| 主要用途 | 声明变量,根据初始化器推导类型 | 查询表达式的类型 |
| 初始化要求 | 必须初始化 | 不需要初始化 (只是查询类型) |
| 引用处理 | 忽略初始化表达式的引用 | 保留表达式的引用信息 |
顶层 const处理 | 忽略初始化表达式的顶层 const | 保留表达式的顶层 const |
| 括号影响 | 不受括号影响 (auto x = (y); 与 auto x = y; 相同) | decltype((x)) 与 decltype(x) 行为不同 |
| 推导来源 | 基于初始化表达式的值 (忽略引用/const) | 基于表达式的类型和值类别 |
| 常见场景 | 简化变量声明、迭代器、lambda | 精确类型获取、尾置返回类型、元编程 |
4、decltype(auto)(c++14 引入)
c++14 引入了 decltype(auto),它结合了两者的意图:用于变量声明(像 auto),但使用 decltype 的规则进行推导(保留引用和 const)。它相当于对初始化表达式应用 decltype 规则。
int i = 0; int& ref_i = i; const int ci = 1; const int& cref_i = ci; auto a = ref_i; // a 是 int decltype(auto) da = ref_i; // da 是 int& (应用 decltype 规则) auto b = cref_i; // b 是 int decltype(auto) db = cref_i; // db 是 const int& auto c = 5; // c 是 int decltype(auto) dc = 5; // dc 是 int (5 是右值)
decltype(auto) 在需要精确转发返回类型(如在转发函数或通用 lambda 中)时特别有用。
二、示例
好的,这是一个展示 c++ 中 auto 和 decltype 用法的示例:
#include <iostream>
#include <vector>
#include <typeinfo> // 用于打印类型信息(仅作演示,非必需)
int main() {
// 示例 1: 使用 auto 推导变量类型
auto x = 42; // 编译器推导 x 为 int 类型
auto y = 3.14; // 编译器推导 y 为 double 类型
auto vec = std::vector<int>{1, 2, 3}; // 编译器推导 vec 为 std::vector<int> 类型
// 示例 2: 使用 decltype 获取表达式的类型
decltype(x) a = x; // a 的类型与 x 相同 (int)
decltype(3.14 + 1) b; // b 的类型是 3.14(double) + 1(int) 的结果类型 (double)
decltype(vec[0]) element = vec[0]; // element 的类型是 vector 元素类型 (int&)
// 示例 3: auto 在范围 for 循环中的应用
std::cout << "vector elements: ";
for (auto num : vec) { // num 的类型被推导为 int (vec 的元素类型)
std::cout << num << " ";
}
std::cout << std::endl;
// 示例 4: decltype 用于函数返回类型(后置返回类型)
auto add = [](int a, int b) -> decltype(a + b) {
return a + b;
};
auto sum = add(x, 10); // sum 的类型是 decltype(a + b),即 int
// (可选) 打印一些变量的类型信息 (需要 typeid)
std::cout << "type of x: " << typeid(x).name() << std::endl;
std::cout << "type of y: " << typeid(y).name() << std::endl;
std::cout << "type of a: " << typeid(a).name() << std::endl;
std::cout << "type of b: " << typeid(b).name() << std::endl;
std::cout << "type of element: " << typeid(element).name() << std::endl;
std::cout << "type of sum: " << typeid(sum).name() << std::endl;
return 0;
}运行结果:
vector elements: 1 2 3
type of x: int
type of y: double
type of a: int
type of b: double
type of element: int
type of sum: intc:\users\徐鹏\desktop\新建文件夹\project1\x64\debug\project1.exe (进程 34504)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

代码说明:
auto:auto x = 42;: 编译器根据初始值42推导出x的类型为int。auto y = 3.14;: 编译器根据初始值3.14推导出y的类型为double。auto vec = std::vector<int>{1, 2, 3};: 编译器根据初始化列表推导出vec的类型为std::vector<int>。for (auto num : vec): 在范围for循环中,编译器根据容器vec的元素类型推导出num的类型为int。auto add = ...:auto用于推导匿名函数lambda的类型。auto sum = ...:auto推导函数add的返回类型,即int。
decltype:decltype(x) a = x;:decltype(x)获取变量x的声明类型 (int),因此a的类型也是int。decltype(3.14 + 1) b;:decltype(3.14 + 1)计算表达式3.14 + 1的类型(double + int结果为double),因此b的类型是double。decltype(vec[0]) element = vec[0];:decltype(vec[0])获取表达式vec[0]的类型。对于std::vector,operator[]返回引用 (int&),因此element的类型是int&(一个引用)。-> decltype(a + b): 在lambda函数的后置返回类型声明中,使用decltype(a + b)来指定函数的返回类型为表达式a + b的结果类型 (int + int = int)。
typeid:- 这部分代码(需要包含
<typeinfo>)是可选的,仅用于在运行时打印类型名称(如i表示int,d表示double等)。编译器不同,打印的名称格式可能不同(如int或i),这主要用于演示目的。实际编程中通常不需要这样做。
- 这部分代码(需要包含
到此这篇关于c++ auto和decltype的用法和区别全解析的文章就介绍到这了,更多相关c++ auto和decltype用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论