C++11之自動類型推導的實現(xiàn)示例
一、auto 的基本概念
auto 是一個類型占位符,而非一個真正的類型。當你用auto聲明變量時,編譯器會根據(jù)變量的初始化表達式自動推導出變量的實際類型,然后將auto替換為這個類型。
核心要求:用 auto 聲明的變量必須初始化,否則編譯器無法推導類型。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
// 1. 基本類型推導
auto a = 10; // 推導為 int
auto b = 3.14; // 推導為 double
auto c = 'A'; // 推導為 char
auto d = true; // 推導為 bool
auto e = "hello"; // 推導為 const char*(字符串字面量是const char[])
auto f = string("hi");// 推導為 std::string
// 驗證推導結(jié)果(通過typeid查看類型)
cout << typeid(a).name() << endl; // 輸出:int(不同編譯器輸出可能略有差異,比如MSVC輸出int,GCC輸出i)
cout << typeid(e).name() << endl; // 輸出:const char*
// 2. 復雜類型推導(解決冗長類型名問題)
vector<vector<int>> matrix = {{1,2}, {3,4}};
// 傳統(tǒng)寫法:vector<vector<int>>::iterator it = matrix.begin();
auto it = matrix.begin(); // 推導為 vector<vector<int>>::iterator
cout << (*it)[0] << endl; // 輸出:1
return 0;
}
執(zhí)行結(jié)果:
i
PKc
1
GCC/Clang 對復合類型的簡寫規(guī)則:
P= Pointer(指針)K= const(Konst,德語 “常量” 的縮寫,C++ 標準里用K表示 const)c= char所以PKc組合起來就是const char*(按順序:P (指針) + K (const) + c (char))
二、auto 的推導規(guī)則
auto的推導規(guī)則和模板參數(shù)推導基本一致,核心分三種情況:
規(guī)則 1:初始化表達式是普通類型(非引用、非指針)
auto會推導出和初始化表達式完全一致的類型(忽略頂層 const/volatile)。
#include <iostream>
using namespace std;
int main() {
const int x = 10;
auto y = x; // y的類型是int(頂層const被忽略)
y = 20; // 可以修改,證明y不是const
const auto z = x; // z的類型是const int(手動加const,保留常量屬性)
// z = 30; // 編譯錯誤:z是const int,不能修改
volatile int m = 20;
auto n = m; // n的類型是int(頂層volatile被忽略)
return 0;
}
規(guī)則 2:初始化表達式是引用 / 指針
- 如果表達式是引用,auto會推導出被引用的類型(忽略引用);
- 如果表達式是指針,auto會保留指針屬性;
- 如果是底層 const的指針 / 引用,auto會保留底層 const。
#include <iostream>
using namespace std;
int main() {
int val = 100;
int& ref_val = val;
auto a = ref_val; // a的類型是int(忽略引用)
a = 200;
cout << val << endl; // 輸出:100(a是拷貝,不影響val)
auto& b = ref_val; // b的類型是int&(手動加&,保留引用)
b = 200;
cout << val << endl; // 輸出:200(b是引用,修改影響val)
const int c = 50;
const int& ref_c = c;
auto d = ref_c; // d的類型是int(忽略引用,頂層const也忽略)
auto& e = ref_c; // e的類型是const int&(保留底層const和引用)
// e = 60; // 編譯錯誤:e指向const int
int* p = &val;
auto q = p; // q的類型是int*(保留指針)
const int* pc = &c;
auto r = pc; // r的類型是const int*(保留底層const的指針)
return 0;
}
規(guī)則 3:初始化表達式是數(shù)組 / 函數(shù)
- 數(shù)組名作為表達式時,
auto會推導為指針類型; - 函數(shù)名作為表達式時,
auto會推導為函數(shù)指針類型。
#include <iostream>
using namespace std;
void func() {
cout << "func called" << endl;
}
int main() {
int arr[5] = {1,2,3,4,5};
auto a = arr; // a的類型是int*(數(shù)組退化為指針)
cout << *(a+1) << endl; // 輸出:2
auto& b = arr; // b的類型是int (&)[5](數(shù)組的引用,保留數(shù)組類型)
cout << b[2] << endl; // 輸出:3
cout << sizeof(b) << endl; // 輸出:20(5個int,每個4字節(jié))
auto f = func; // f的類型是void (*)()(函數(shù)指針)
f(); // 調(diào)用func,輸出:func called
return 0;
}
三、auto 的核心使用場景
auto不是 “萬能的”,但在以下場景能極大提升代碼可讀性和開發(fā)效率:
場景 1:簡化冗長的類型名
這是auto最核心的用途,尤其是 STL 容器的迭代器、函數(shù)返回值類型復雜的場景。
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
// 復雜容器的迭代器
map<string, map<int, string>> complex_map;
complex_map["user1"][1001] = "Tom";
// 傳統(tǒng)寫法(冗長且易出錯):
// map<string, map<int, string>>::iterator it = complex_map.begin();
auto it = complex_map.begin(); // 簡潔明了
cout << it->first << ": " << it->second[1001] << endl; // 輸出:user1: Tom
return 0;
}
場景 2:遍歷容器(配合范圍 for 循環(huán))
這是 C++11 后最常用的組合寫法,徹底擺脫手動管理迭代器 / 索引。
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums = {10,20,30,40};
// 只讀遍歷(拷貝)
for (auto val : nums) {
cout << val << " ";
}
cout << endl;
// 修改遍歷(引用)
for (auto& val : nums) {
val *= 2;
}
// 只讀遍歷(const引用,避免拷貝,效率更高)
for (const auto& val : nums) {
cout << val << " "; // 輸出:20 40 60 80
}
return 0;
}
場景 3:配合 Lambda 表達式
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> nums = {3,1,4,1,5,9};
// Lambda表達式的變量必須用auto聲明
auto compare = [](int a, int b) { return a > b; };
sort(nums.begin(), nums.end(), compare);
for (auto val : nums) {
cout << val << " "; // 輸出:9 5 4 3 1 1
}
return 0;
}
場景 4:處理模板類型
在模板編程中,auto可以簡化模板參數(shù)推導后的類型聲明。
#include <iostream>
using namespace std;
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) { // C++11尾返回類型(配合auto)
return a + b;
}
int main() {
auto res1 = add(10, 20.5); // res1推導為double(10+20.5=30.5)
auto res2 = add(5, 3); // res2推導為int(5+3=8)
cout << res1 << " " << res2 << endl; // 輸出:30.5 8
return 0;
}
四、auto 的注意事項(避坑指南)
1. 必須初始化
auto是 “推導” 類型,沒有初始化值就無法推導,編譯會報錯。
// 錯誤示例 auto x; // 編譯錯誤:auto變量必須初始化 x = 10;
2. 不能用于函數(shù)參數(shù)
auto不能直接作為函數(shù)參數(shù)類型(C++14 支持auto作為函數(shù)返回值,但參數(shù)仍不支持)。
// 錯誤示例
void func(auto x) { // 編譯錯誤:參數(shù)不能用auto
cout << x << endl;
}
// 正確替代方案:用模板
template <typename T>
void func(T x) {
3. 不能用于數(shù)組聲明
auto不能直接聲明數(shù)組,但可以推導數(shù)組的引用或指針。
// 錯誤示例
auto arr[5] = {1,2,3,4,5}; // 編譯錯誤:auto不能聲明數(shù)組
// 正確寫法
int raw_arr[5] = {1,2,3,4,5};
auto* arr_ptr = raw_arr; // 推導為int*
auto& arr_ref = raw_arr; // 推導為int (&)[5]
4.推導可能 “丟失” const / 引用屬性
如前面的規(guī)則所述,auto默認會忽略頂層 const 和引用,如需保留,需手動加const/&。
int val = 10; const int& ref = val; auto a = ref; // a是int,丟失const和引用 const auto& b = ref;// b是const int&,保留屬性
5. 避免過度使用
auto能簡化代碼,但過度使用會降低可讀性(比如簡單類型也用 auto)。
// 不推薦(可讀性差) auto x = 10; // 直接寫int x = 10更清晰 // 推薦(類型冗長) vector<map<int, string>> vec; auto it = vec.begin(); // 比寫完整迭代器類型更清晰
到此這篇關(guān)于C++11之自動類型推導的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C++11 自動類型推導內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)實例講解單鏈表的實現(xiàn)
單鏈表是后面要學的雙鏈表以及循環(huán)鏈表的基礎(chǔ),要想繼續(xù)深入了解數(shù)據(jù)結(jié)構(gòu)以及C++,我們就要奠定好這塊基石!接下來就和我一起學習吧2022-03-03
C++實現(xiàn)LeetCode(153.尋找旋轉(zhuǎn)有序數(shù)組的最小值)
這篇文章主要介紹了C++實現(xiàn)LeetCode(153.尋找旋轉(zhuǎn)有序數(shù)組的最小值),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
C++ Primer Plus 第四章之C++ Primer Plus復合類型學習筆記
數(shù)組(array)是一種數(shù)據(jù)格式,能夠存儲多個同類型的值。每個值都存儲在一個獨立的數(shù)組元素中,計算機在內(nèi)存中依次存儲數(shù)組的各個元素,今天給大家重點介紹C++ Primer Plus復合類型的實例詳解,感興趣的朋友一起看看吧2021-07-07

