从零到一学习c++(基础篇--筑基期四-auto、decltype)

 从零到一学习C++(基础篇) 作者:羡鱼肘子

 温馨提示1:本篇是记录我的学习经历,会有不少片面的认知,万分期待您的指正。

 温馨提示2:本篇会尽量避免一些术语,尽量用更加通俗的语言介绍c++的基础,但术语也是很重要的。

 温馨提示3:看本篇前可以先了解前篇的内容,知识体系会更加完整哦。

从零到一学习c++(基础篇--筑基期三-const限定符)-优快云博客

auto类型说明符 

C++ 中的 auto 是一个类型说明符,用于让编译器自动推导变量类型。它从 C++11 开始引入,是现代 C++ 中简化代码、增强可读性的重要工具。

1. 核心作用:自动类型推断

 auto 的核心逻辑是:编译器根据初始化表达式自动确定变量类型。类似于“让编译器猜类型”,但规则明确,不会出错。

基础用法示例
auto a = 42;         // a 的类型是 int
auto b = 3.14;       // b 的类型是 double
auto c = "Hello";    // c 的类型是 const char*
auto d = 'A';        // d 的类型是 char

2.为什么用 auto

  • 简化复杂类型声明:尤其是模板、迭代器等冗长类型。

  • 避免类型重复书写:代码更简洁。

  • 支持泛型编程:处理未知类型更方便。

简化迭代器的作用
// 传统写法(类型冗长)
std::vector<int> vec = {1, 2, 3};
std::vector<int>::iterator it = vec.begin();

// 使用 auto(简洁明了)
auto it = vec.begin();  // 自动推导为 std::vector<int>::iterator

3. auto 的推导规则

简单理解:可以把auto看成“还原剂”,对引用和顶层const起反应

  • 去掉引用和顶层 const
    auto 默认推导为值类型,引用和 const 需要显式声明。

  • 保留底层 const
    若初始化表达式是底层 const(如 const int*),auto 会保留。

强化理解:底层const  VS 顶层const(这一部分很难但也很重要)

在这一部分我会用比较专业的用语来解释,因为我认为在这一块一味的通俗比方很可能会让人“误入歧途”

 顶层const(Top-Level Const)
  • 定义:直接修饰变量本身,表示该变量不可修改。

  • 特点

    • 适用于所有数据类型(基本类型、指针、类对象等)。

    • 对象本身是常量,任何修改操作都会导致编译错误。

const int a = 10;       // a是顶层const,值不可修改
int *const p = &b;      // p是顶层const,指针本身不可修改(指向的地址固定)
const double pi = 3.14; // pi是顶层const
应用场景
  • 定义全局常量或需要保护不被修改的局部变量。

  • 固定指针的指向地址(如硬件寄存器指针)。

 底层const(Low-Level Const)
  • 定义:修饰指针引用所指向的对象,表示不能通过该指针或引用修改目标对象。

  • 特点

    • 仅适用于指针或引用类型。

    • 指向的对象本身可能是常量或非常量,但通过该指针/引用无法修改。

const int *p = &a;      // p是底层const,不能通过p修改a的值
const int &r = a;       // r是底层const,不能通过r修改a的值
const std::string *s;   // s指向的字符串内容不可修改
应用场景
  • 函数参数传递时,避免意外修改传入的数据。

  • 处理常量数据(如字符串字面量、配置文件等)。

顶层const vs 底层const对比
特性顶层const底层const
修饰对象变量本身指针/引用指向的对象
适用类型所有类型仅指针和引用
函数重载无法区分重载可以区分重载
参数传递严格匹配类型接受常量或非常量实参
典型示例int *const pconst int *p
 小结一下:
  • 顶层const:保护变量本身不被修改,适用于所有类型。

  • 底层const:保护指针或引用指向的内容不被修改,增强代码安全性,“只读”访问。

  • 要合理使用哦

    • 函数参数优先使用底层const,提高接口通用性。

    • 顶层const用于需要固定变量或指针地址的场景。

欧克,我们来找个例子看看 
int x = 10;
const int y = 20;
int& ref = x;
const int* ptr = &y;

// auto 推导
auto a = x;       // a 是 int
auto b = ref;     // b 是 int
auto c = ptr;     // c 是 const int*
auto d = &y;      // d 是 const int*
  • 去引用(Reference Stripping)
    auto b = ref; 中,ref 是 int& 类型,但 auto 会推导为 int(值类型),而非引用。
    结果b 是独立的 int 变量,值为 x 的拷贝(10)。

  • 保留底层 const(Pointer to Const)
    const int* ptr = &y; 中,ptr 是“指向常量整型的指针”。
    auto 推导auto c = ptr; 会保留底层 const,因此 c 的类型是 const int*(正确)。auto d = &y; 中,y 是 const int,其地址类型为 const int*结果d 的类型是 const int*(正确)。

显式保留引用或 const
int x = 10;
const int y = 20;

auto& a = x;       // a 是 int&(保留引用)
const auto& b = y; // b 是 const int&(保留引用和 const)
auto* c = &x;      // c 是 int*(显式指针类型)

4. 常见使用场景

(1) 简化迭代器和范围 for 循环
std::vector<int> vec = {1, 2, 3};
// 传统迭代器写法
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { ... }

// 使用 auto + 范围 for 循环
for (auto num : vec) { ... }        // 值拷贝
for (auto& num : vec) { ... }       // 引用(可修改元素)
for (const auto& num : vec) { ... } // 常量引用(只读)
(2) 泛型编程中的未知类型(目前可以跳过)
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { // C++11 需要尾置返回类型
    return a + b;
}

// C++14 更简洁
template<typename T, typename U>
auto add(T a, U b) {
    return a + b;
}

auto result = add(3, 4.5); // result 类型为 double
(3) Lambda 表达式
auto lambda = [](int a, int b) { return a + b; };
auto sum = lambda(3, 4); // sum 类型为 int

5. auto 的注意事项

(1) 必须初始化
auto a; // 错误!无法推导类型
(2) 推导结果可能与预期不同(目前了解一下就好)
const int x = 10;
auto y = x;        // y 是 int(去掉了顶层 const)
auto& z = x;       // z 是 const int&(保留 const)

int arr[] = {1, 2, 3};
auto arr_copy = arr; // arr_copy 是 int*(数组退化为指针)
auto& arr_ref = arr; // arr_ref 是 int(&)[3](保留数组类型)
(3) 函数返回类型推导(C++14+)
auto func() {       // 返回类型由 return 语句推导
    return 42;      // 返回 int
}

auto func2() {      // 返回类型需一致
    if (condition) return 10; // int
    else return 3.14;         // double → 错误!
}

6. auto vs decltype

  • auto:根据初始化表达式推导类型。

  • decltype:根据表达式推导类型,但不计算表达式的值。

int x = 10;
const int& y = x;

auto a = y;        // a 是 int(去掉了引用和顶层 const)
decltype(y) b = x; // b 是 const int&(精确匹配表达式类型)

最终建议:合理使用 auto,既能提高编码效率,又能减少低级错误!🚀

decltype 

decltype 是 C++11 引入的关键字,用于推导表达式的类型。它的核心逻辑是:“告诉我某个表达式是什么类型,但不要实际计算它的值”

 基础用法:直接获取类型

decltype(表达式) 会返回表达式的精确类型(包括 const、引用等修饰符)。

int x = 10;
const double y = 3.14;
int& ref = x;

decltype(x) a = x;          // a 的类型是 int
decltype(y) b = y;          // b 的类型是 const double
decltype(ref) c = x;        // c 的类型是 int&(引用)
decltype(x + y) d = x + y;  // d 的类型是 double(int + double → double)
与 auto 的关键区别
特性autodecltype
推导依据根据初始化表达式推导类型根据传入的表达式推导类型
引用和 const默认忽略顶层 const 和引用保留所有修饰符(包括引用和 const
计算表达式值必须初始化(依赖表达式值)不计算表达式的值(仅分析类型)
对比示例
int x = 10;
const int& rx = x;

auto a = rx;        // a 是 int(忽略引用和 const)
decltype(rx) b = x; // b 是 const int&(保留所有修饰符)

常见用途

(1) 定义复杂类型别名
#include <vector>
using Vec = std::vector<int>;

Vec vec = {1, 2, 3};
decltype(vec)::iterator it = vec.begin(); // 等价于 std::vector<int>::iterator
(2) 泛型编程中的返回值类型推导
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { // C++11 需要尾置返回类型
    return a + b;
}

auto result = add(3, 4.5); // result 类型为 double
(3) 保留引用类型(避免拷贝)
std::vector<int> vec = {1, 2, 3};
decltype(vec[0]) elem = vec[0]; // elem 是 int&(引用vec中的元素)
elem = 10;                      // 修改vec[0]为10

 特殊规则

(1) 变量 vs 表达式
  • 变量名decltype(var) 返回变量的声明类型(含 const 和引用)。

  • 表达式decltype(表达式) 可能推导出引用类型(如 (x) 会变成 int&)。

int x = 10;
decltype(x) a = x;   // a 是 int
decltype((x)) b = x; // b 是 int&(表达式 (x) 被视为左值)
(2) 结合 declval 推导类成员类型
#include <utility>
struct Point {
    int x;
    double y;
};

// 推导Point的成员x的类型
using XType = decltype(std::declval<Point>().x); // XType 是 int

C++14 扩展:decltype(auto)

  • 用途:结合 auto 的简洁性和 decltype 的精确性,常用于函数返回类型。

  • 规则:返回类型由 decltype(return表达式) 决定。

 注意事项

  • 不计算表达式值decltype 只分析类型,不会执行表达式。

    int x = 10;
    decltype(x++) y = x; // y 是 int(x++ 的类型是 int,但不会真的执行x++)
  • 避免冗余修饰符

    const int x = 10;
    decltype(x) a = 20;  // a 是 const int,但初始化后不能修改

类比decltype 像一台“类型复印机”,原样复制表达式的类型细节。📋🔍

 下一篇会学习数组,让我们一起加油。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚戏师

多谢道友

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值