C++ auto和decltype的用法和区别全解析

 更新时间:2026年01月22日 11:38:35   作者:小灰灰搞电子  
这篇文章介绍了C++11和C++14中auto和decltype关键字的用法和区别,auto用于自动类型推导,适用于变量声明,简化代码并提高可维护性,decltype用于查询表达式的类型,保留表达式的完整类型信息,感兴趣的朋友跟随小编一起看看吧

一、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 获取其类型(虽然通常更常用 autostd::function)。
auto lambda = []{ return 42; };
decltype(lambda) anotherLambda = lambda; // anotherLambda 是同类型 Lambda

3、auto和decltype的区别总结

特性autodecltype
主要用途声明变量,根据初始化器推导类型查询表达式的类型
初始化要求必须初始化不需要初始化 (只是查询类型)
引用处理忽略初始化表达式的引用保留表达式的引用信息
顶层 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++ 中 autodecltype 用法的示例:

#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: int

C:\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::vectoroperator[] 返回引用 (int&),因此 element 的类型是 int&(一个引用)。
    • -> decltype(a + b): 在 lambda 函数的后置返回类型声明中,使用 decltype(a + b) 来指定函数的返回类型为表达式 a + b 的结果类型 (int + int = int)。
  • typeid:
    • 这部分代码(需要包含 <typeinfo>)是可选的,仅用于在运行时打印类型名称(如 i 表示 int, d 表示 double 等)。编译器不同,打印的名称格式可能不同(如 inti),这主要用于演示目的。实际编程中通常不需要这样做。

到此这篇关于C++ auto和decltype的用法和区别全解析的文章就介绍到这了,更多相关C++ auto和decltype用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言 超详细顺序表的模拟实现实例建议收藏

    C语言 超详细顺序表的模拟实现实例建议收藏

    程序中经常需要将一组数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等。一组数据中包含的元素个数可能发生变化,顺序表则是将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示
    2022-03-03
  • C语言实现骑士飞行棋小游戏

    C语言实现骑士飞行棋小游戏

    这篇文章主要为大家详细介绍了C语言实现骑士飞行棋小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C++设计模式之策略模式

    C++设计模式之策略模式

    这篇文章主要介绍了C++设计模式之策略模式,本文讲解了什么是策略模式、策略模式的使用场合、策略模式的代码实例等内容,需要的朋友可以参考下
    2014-10-10
  • 用Visual Studio2017写C++静态库图文详解

    用Visual Studio2017写C++静态库图文详解

    这篇文章主要介绍了用Visual Studio2017写C++静态库的图文教程,需要的朋友可以参考下
    2017-04-04
  • C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

    C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

    在上一章中我们正式开启了对数据结构中树的讲解,介绍了树的基础。本章我们将学习二叉树的概念,介绍满二叉树和完全二叉树的定义,并对二叉树的基本性质进行一个简单的介绍。本章附带课后练习
    2022-02-02
  • visual studio 2019工具里添加开发中命令提示符的方法

    visual studio 2019工具里添加开发中命令提示符的方法

    这篇文章主要介绍了visual studio 2019工具里添加开发中命令提示符的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • C++中stack的pop()函数返回值解析

    C++中stack的pop()函数返回值解析

    这篇文章主要介绍了C++中stack的pop()函数返回值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Qt实现自定义矩阵布局

    Qt实现自定义矩阵布局

    这篇文章主要为大家详细介绍了Qt实现自定义矩阵布局,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • VC++文件监控之ReadDirectoryChangesW

    VC++文件监控之ReadDirectoryChangesW

    文章主要介绍文件监控的另一种实现方式,利用ReadDirectoryChangesW来实现文件的监控,希望对大家有帮助
    2019-04-04
  • 深入C++可见性与生命期的区别详解

    深入C++可见性与生命期的区别详解

    本篇文章对C++中可见性与生命期的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论