欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > auto关键字、decltype关键字

auto关键字、decltype关键字

2025/3/9 10:17:18 来源:https://blog.csdn.net/m0_48241022/article/details/146075597  浏览:    关键词:auto关键字、decltype关键字

目录

二、auto类型说明符/auto关键字

2.1 定义 

2.2  复合类型、常量和auto

三、decltype类型指示符/decltype关键字

3.1 decltype 基本语法 

 3.2 定义及用法

3.3 decltype和引用

四、总结


二、auto类型说明符/auto关键字

2.1 定义 

auto 是类型说明符,通过变量的初始值来推断变量的类型。

编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型。然而要做到这一点并非那么容易,有时甚至根本做不到,为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应一种特定类型的说明符(比如double)不同,auto让编译器通过初始值来推算变量的类型。

显然,auto定义的变量必须有初始值:

定义两个相同类型的变量,如下: 

#include<iostream>int main(){int val1=10;int val2=3;auto add = val1+val2;std::cout<<typeid(add).name()<<std::endl; // 输出:i,说明add的类型是int类型return 0;
}

 定义两个不同类型的变量,让auto自动判断二者之和的类型,如下:

#include<iostream>int main(){int val1=10;double val2=3.2;auto add = val1+val2;std::cout<<typeid(add).name()<<std::endl; // 输出:d,说明add的类型是double类型return 0;
}

 此处编译器将根据 val1和val2相加的结果来推断add的类型。

#include<iostream>
#include<vector>
int main(){std::vector<int> nums{1,2,3};auto a = nums; // a是一个整数(r是i的别名,而i是一个整数)std::cout<<typeid(a).name()<<std::endl; //输出:St6vectorIiSaIiEEreturn 0;
}

对上述代码输出结果的分析:

在 C++ 中,typeid(a).name() 返回的是 a 的类型名称,不过其输出通常是 实现依赖的(implementation-dependent),即不同的编译器可能会生成不同的表示方式。在你的代码中,typeid(a).name() 的输出是:

St6vectorIiSaIiEE

如何解析 St6vectorIiSaIiEE

这是 GCC(GNU Compiler Collection)编译器的 name mangling(名称修饰)格式,它将 C++ 类型转换为一种内部表示。我们来拆解它:

  1. St6vector

    • St 代表 std:: 命名空间(标准库的命名空间)。
    • 6vector 表示 std::vector,其中 6 表示 vector 这个单词的长度(GCC 采用这种方式来存储标识符的长度)。
  2. Ii

    • I 表示 模板参数列表开始(Template Parameter List)。
    • i 代表 int 类型,即 std::vector<int>
  3. SaIiEE

    • Sa 代表 allocator(分配器),即 std::allocator<int>
    • Ii 再次表示 int 类型(allocator 的模板参数)。
    • E 表示 模板参数列表结束

综合解析

St6vectorIiSaIiEE

翻译回 C++,就是:

std::vector<int, std::allocator<int>>

由于 std::vector 的默认分配器就是 std::allocator<T>,所以简写就是:

std::vector<int>

代码中的 auto 推导

std::vector<int> nums{1,2,3};
auto a = nums;
  • auto a = nums;
    • numsstd::vector<int>,所以 a 也会被推导为 std::vector<int>值拷贝)。
    • 也就是说,anums 的一个 拷贝,而不是引用。

总结

  • St6vectorIiSaIiEEGCC 编译器对 std::vector<int> 类型的编码
  • auto a = nums; a 的类型是 std::vector<int>,并且是值拷贝
  • 如果希望 a 成为 nums 的引用,应该使用 auto& a = nums;。🚀

 

使用auto也能在一条语句中声明多个变量。因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样:

#include<iostream>int main(){auto i=0,*p=&i; // 正确:i是整数、p是整型指针auto sz=0,pi=3.14; // 错误:sz和pi的类型不一致return 0;
}

2.2  复合类型、常量和auto

编译器推断出来的 auto 类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。

首先,使用引用其实就是使用引用的对象,特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:

#include<iostream>int main(){int i=0,&r=i; // 定义一个int类型的变量i,同时定义一个int类型的引用,将这个引用绑定在i对象上auto a = r; // a是一个整数(r是i的别名,而i是一个整数)return 0;
}

其次,auto一般会忽略掉顶层const ,同时底层const则会保留下来,比如当初始值是一个指向常量的指针时:

#include<iostream>
int main(){int i=1;const int ci=i,&cr=ci; // 定义一个常量ci,定义一个常量引用cr,cr绑定到ci对象上auto b=ci; // ci的类型是const int,但b的类型是int(ci的顶层const特性被忽略)auto c=cr; // c的类型是int型(cr是ci的别名,ci本身是一个顶层const)auto d=&i; // d是一个int类型的指针auto e=&ci; // e是一个指向整数常量的指针(对常量对象取地址是一种底层const)return 0;
}

如果希望推断出来的auto类型是一个顶层const,需要明确指出:

#include<iostream>
int main(){int i=1;const auto f=i; // i的类型是int,但f的类型是const intreturn 0;
}

 还可以将引用的类型设为auto,此时原来的初始化规则仍然适用:

#include<iostream>
int main(){int i=1;auto &h=i; // h是一个整型常量引用,绑定到i对象上auto &m=42; // ❌错误:不能为非常量引用绑定字面值const auto &n=42; // √正确:可以为常量引用绑定字面值return 0;
}

设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留。和往常一样,如果我们给初始值绑定一个引用,则此时的常量就不是顶层常量了,会变成底层常量。 

上面这句话的意思是:

  • 如果 auto 作为引用(auto&),它会保留初始值的 const 限定符
  • 如果 auto 不是引用,顶层 const 会被忽略(因为 auto 进行类型推导时会去掉顶层 const)。
  • 如果 auto 绑定的是引用,则 const 变成底层 const,即 const 作用在引用对象上,而不是 auto 本身

举例:

  • const int x = 42;

    • x 是一个 顶层 const,即 const 作用于 x 本身,而不是它的内容。
  • auto a = x;

    • auto 推导 x 的类型时,会忽略顶层 const,所以 a 的类型是 int,而不是 const int
    • 这意味着 a 不是 const,可以被修改:
      a = 10; // ✅ 合法
      
  • auto& b = x;

    • b 是一个引用,所以它会保留 xconst 限定符。
    • 这意味着 b 的类型是 const int&,所以 b 不能被修改:
      b = 10; // ❌ 报错,b 是 const int&
      

  • 总结

    变量声明auto 推导结果const 是否保留说明
    auto a = x;int❌ 忽略顶层 consta 可修改
    auto& b = x;const int&const 变成底层 constb 不能修改

    如果你想让 auto 保留 const,可以显式加上 const

    const auto a = x;  // a 现在是 const int
    

    希望这个解释清楚了!🚀

要在一条语句中定义多个变量,切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型:

#include<iostream>
int main(){int i=1;auto a=i,&b=i; // a是整数,b是整型引用const int j=2;auto &m=j,*p=&j; // m是对整型常量的引用,p是指向整型常量的指针auto &n=i,*p2=&j;// ❌错误:i的类型是int而&j的类型是const intreturn 0;
}

三、decltype类型指示符/decltype关键字

decltype 是一个类型说明符,从变量或表达式推断得到类型。如果希望 从表达式推断出变量的类型,但不使用该表达式的值进行初始化,可以使用 decltype 进行类型推导,并显式地 定义变量但不初始化

#include <iostream>int main() {int x = 10;decltype(x) y;  // y 的类型是 int,但未初始化y = 20; // 之后可以手动赋值std::cout << "y = " << y << std::endl;return 0;
}

解析

  • decltype(x) y;
    • y 的类型 x 相同(即 int)。
    • y 没有使用 x 进行初始化
  • y = 20;
    • 变量 y 可以在后续手动赋值。

对比 auto

如果使用 auto,必须 提供初始值

auto y = x; // 必须初始化 y

decltype(x) y; 不需要初始化,可以先声明变量,稍后再赋值。

适用场景

  • 当你想 推导变量类型,但不想立刻初始化变量时,可以使用 decltype
  • 在某些场景下,例如 延迟初始化手动控制赋值逻辑,可以避免 auto 的强制初始化要求。

🚀 这样可以获得类型推导的便利,同时保留初始化的灵活性!

3.1 decltype 基本语法 

decltype(表达式) 变量名;
  • decltype(表达式) 会获取 表达式的确切类型,包括 const 修饰符和引用修饰符。
  • 变量名 的类型将与 decltype(表达式) 推导的类型相同。

 3.2 定义及用法

有时候会遇到这种情况:希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量。为了满足这一要求,C++11新标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

decltype(f()) sum=x; // sum的类型就是函数f的返回类型

编译器并不实际调用函数f,而是使用当调用发生时f的返回值类型作为sum的类型。换句话说,编译器为sum指定的类型是什么呢?就是假如f被调用的话将会返回那个类型。  

decltype处理顶层const和引用的方式与auto有所不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内):

#include <iostream>int main() {const int a=10; // a是一个顶层常量(自己本身就是一个不可变的常量)const int &b=a; // b的类型是const int&decltype(a) x=11.1; // 即使右边的11.1属于double类型,但x的类型是const int类型decltype(b) y=a; // y的类型是const int&,y绑定到变量xdecltype(b) z; // ❌错误:z是一个引用,必须初始化【b是一个引用,decltype(b)的结果就是引用类型,因此作为引用的z必须被初始化】int m=1;decltype(m) g; // 正确:g是一个int整型,可以不用初始化
}

3.3 decltype和引用

如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。有些表达式将向decltype返回一个引用类型,一般来说当这种情况发生时,意味着该表达式的结果对象能作为一条赋值语句的左值:

#include <iostream>int main() {int i=42, *p=&i, &r=i;decltype(r+0) b; // 正确:加法的结果是int,因此b是一个(未初始化的)intdecltype(*p) c; // c是int&,必须初始化return 0;
}

四、总结

autodecltype 都是 C++11 引入的 类型推导 关键字,但它们的用途和行为有所不同。下面详细分析 相同点不同点,并通过示例说明。


相同点

  1. 都用于自动类型推导

    • auto 主要用于变量声明时自动推导类型。
    • decltype 用于获取表达式的类型
  2. 都可以用于泛型编程

    • auto 让函数返回值或变量声明更加灵活。
    • decltype 可以用于模板编程,以推导复杂表达式的类型。

不同点

特性autodecltype
主要用途变量类型推导获取表达式的类型
是否忽略顶层 const✅ 忽略❌ 保留
是否保留引用❌ 一般不保留✅ 保留
推导方式根据变量初始化的值推导类型根据表达式的实际类型推导
是否需要初始化✅ 必须初始化❌ 可以只依赖已有变量

示例 1:顶层 const 的影响

#include <iostream>
#include <type_traits>int main() {const int x = 42;auto a = x;        // `auto` 忽略顶层 `const`decltype(x) b = x; // `decltype` 保留 `const`std::cout << std::is_const<decltype(a)>::value << std::endl; // 输出 0 (false)std::cout << std::is_const<decltype(b)>::value << std::endl; // 输出 1 (true)return 0;
}

🔹 auto 忽略 const,所以 aint,而 decltype 保留 const,所以 bconst int


示例 2:引用的影响

#include <iostream>
#include <type_traits>int main() {int value = 10;int& ref = value;auto a = ref;        // `auto` 推导为 `int`decltype(ref) b = value; // `decltype` 推导为 `int&`std::cout << std::is_reference<decltype(a)>::value << std::endl; // 输出 0 (false)std::cout << std::is_reference<decltype(b)>::value << std::endl; // 输出 1 (true)return 0;
}

🔹 auto 会去掉引用,而 decltype 会保留引用,所以 aintb 仍然是 int&


示例 3:表达式推导

#include <iostream>int main() {int x = 5, y = 10;auto sum1 = x + y;   // `auto` 推导为 `int`decltype(x + y) sum2; // `decltype` 也是 `int`return 0;
}

🔹 decltype 获取的是表达式 x + y 的类型,而 auto 直接从初始化值推导


示例 4:指针和引用

#include <iostream>int main() {int x = 5;int* ptr = &x;auto a = ptr;       // `auto` 推导为 `int*`decltype(ptr) b;    // `decltype` 也是 `int*`return 0;
}

🔹 autodecltype 在指针的情况下,推导结果是相同的。


示例 5:函数返回值

#include <iostream>int foo() { return 42; }
int& bar() { static int x = 10; return x; }int main() {auto a = foo();      // `auto` 推导为 `int`decltype(foo()) b;   // `decltype(foo())` 也是 `int`auto c = bar();      // `auto` 推导为 `int`decltype(bar()) d = bar(); // `decltype(bar())` 保留 `int&`return 0;
}

🔹 decltype 会保留 int&,而 auto 会去掉 &,所以 cintd 仍然是 int&


示例 6:decltype(auto)

C++14 引入了 decltype(auto),它结合了 autodecltype 的特性,能够保留 const 和引用:

#include <iostream>int x = 10;
int& foo() { return x; }int main() {auto a = foo();         // `auto` 推导为 `int`decltype(auto) b = foo(); // `decltype(auto)` 推导为 `int&`return 0;
}

🔹 decltype(auto) 既保留 const,也保留引用,可以更准确地推导类型。


总结

关键字作用是否忽略 const是否保留引用典型用途
auto变量类型推导✅ 忽略❌ 去掉引用声明变量
decltype获取表达式的类型❌ 保留✅ 保留模板编程、泛型
decltype(auto) (C++14)结合 autodecltype❌ 保留✅ 保留适用于函数返回值

何时使用 autodecltype

  • 使用 auto

    • 变量声明时,如果不关心 const 和引用(例如 auto x = 42;)。
    • 代码可读性更强,避免写冗长的类型。
    • for-range 循环中:
      for (auto x : vec) { ... }
      
    • auto& 绑定到 const 变量时,const 会被保留:
      const int x = 10;
      auto& y = x;  // y 是 `const int&`
      
  • 使用 decltype

    • 需要获取表达式的真实类型(特别是涉及函数返回值时)。
    • 需要保留 const 或引用:
      decltype(x) y = x;  // y 和 x 的类型完全相同
      
    • 在模板和泛型编程中:
      template<typename T>
      decltype(auto) get_value(T&& t) {return std::forward<T>(t);
      }
      

🚀 总结:

  • auto 进行变量类型推导,默认忽略 const 和引用。
  • decltype 获取表达式的真实类型,默认保留 const 和引用。
  • decltype(auto) 在需要 decltype 但想让代码更简洁时使用。

希望这个总结对你有帮助!🔥🚀

 

这道题目考察 decltypeauto 之间的区别,要求分别举例说明两者 类型相同类型不同 的情况。


1. decltype 指定的类型与 auto 指定的类型一样

autodecltype 作用于 普通变量 时,它们的推导结果相同:

#include <iostream>int main() {int x = 10;auto a = x;      // auto 推导出的类型是 intdecltype(x) b = x; // decltype 推导出的类型也是 intstd::cout << typeid(a).name() << " " << typeid(b).name() << std::endl;return 0;
}

解析

  • auto a = x;a 的类型是 int
  • decltype(x) b = x;b 的类型也是 int
  • 两者推导结果相同。

2. decltype 指定的类型与 auto 指定的类型不一样

auto 作用于 引用类型 时,它会 忽略引用,但 decltype 保留引用

#include <iostream>int main() {int x = 10;int& ref = x;auto a = ref;       // auto 忽略引用,a 的类型是 intdecltype(ref) b = x; // decltype 保留引用,b 的类型是 int&a = 20;  // 只修改 a,不影响 xb = 30;  // 由于 b 是 x 的引用,修改 b 也会影响 xstd::cout << "x: " << x << ", a: " << a << ", b: " << b << std::endl;return 0;
}

解析

  • auto a = ref;a 的类型是 int(忽略引用)。
  • decltype(ref) b = x;b 的类型是 int&(保留引用)。
  • 区别
    • aint,修改 a 不会影响 x
    • bint&,修改 b 会影响 x

总结

场景autodecltype
作用于普通变量保留类型保留类型
作用于引用忽略引用保留引用
作用于 const忽略 const保留 const

这道题考察 decltypeauto类型推导 方面的区别,特别是 是否保留引用和 const,理解这些差异有助于编写更灵活和精准的 C++ 代码。 🚀

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词