Serie: C++
cpp
406 righe
· Aggiornato 2026-04-03
auto_decltype.cpp
C++/Part5_進階主題/Ch21_型別推導/auto_decltype.cpp
// auto_decltype.cpp
// 編譯指令:g++ -std=c++17 -Wall auto_decltype.cpp -o auto_decltype
//
// 本程式示範 auto 與 decltype 的型別推導規則
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
// 輔助函式:取得可讀的型別名稱
template<typename T>
std::string type_name() {
int status;
char* demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
std::string result = (status == 0) ? demangled : typeid(T).name();
free(demangled);
return result;
}
// ============================================================
// 第一部分:auto 基本用法
// ============================================================
void demo_auto_basics() {
std::cout << "========================================\n";
std::cout << " auto 基本型別推導\n";
std::cout << "========================================\n\n";
auto i = 42; // int
auto d = 3.14; // double
auto f = 3.14f; // float
auto c = 'A'; // char
auto b = true; // bool
auto s = "hello"; // const char*
auto str = std::string("hello"); // std::string
std::cout << "auto i = 42; -> " << type_name<decltype(i)>() << "\n";
std::cout << "auto d = 3.14; -> " << type_name<decltype(d)>() << "\n";
std::cout << "auto f = 3.14f; -> " << type_name<decltype(f)>() << "\n";
std::cout << "auto c = 'A'; -> " << type_name<decltype(c)>() << "\n";
std::cout << "auto b = true; -> " << type_name<decltype(b)>() << "\n";
std::cout << "auto s = \"hello\"; -> " << type_name<decltype(s)>() << "\n";
std::cout << "auto str = string(...); -> " << type_name<decltype(str)>() << "\n";
std::cout << "\n";
}
// ============================================================
// 第二部分:auto 與 const 的交互
// ============================================================
void demo_auto_const() {
std::cout << "========================================\n";
std::cout << " auto 與 const\n";
std::cout << "========================================\n\n";
const int ci = 100;
auto a = ci; // int — 忽略頂層 const
const auto b = ci; // const int — 手動加 const
std::cout << "const int ci = 100;\n";
std::cout << "auto a = ci; -> " << type_name<decltype(a)>()
<< " (頂層 const 被忽略)\n";
std::cout << "const auto b = ci; -> " << type_name<decltype(b)>()
<< " (手動保留 const)\n";
a = 200; // 合法,a 不是 const
// b = 200; // 編譯錯誤,b 是 const
std::cout << "a 可以被修改: a = " << a << "\n";
// 指標的情況:底層 const 會被保留
const int* pc = &ci;
auto c = pc; // const int* — 底層 const 被保留
std::cout << "\nconst int* pc = &ci;\n";
std::cout << "auto c = pc; -> " << type_name<decltype(c)>()
<< " (底層 const 保留)\n";
std::cout << "\n";
}
// ============================================================
// 第三部分:auto 與參考
// ============================================================
void demo_auto_reference() {
std::cout << "========================================\n";
std::cout << " auto 與參考\n";
std::cout << "========================================\n\n";
int x = 42;
int& rx = x;
auto a = rx; // int — 忽略參考,a 是副本
auto& b = rx; // int& — 明確使用 auto&,b 參考 x
const auto& c = rx; // const int& — 唯讀參考
std::cout << "int x = 42; int& rx = x;\n";
std::cout << "auto a = rx; -> " << type_name<decltype(a)>()
<< " (參考被忽略,a 是副本)\n";
std::cout << "auto& b = rx; -> " << type_name<decltype(b)>()
<< " (保留參考)\n";
std::cout << "const auto& c = rx; -> " << type_name<decltype(c)>() << "\n\n";
// 驗證:修改 a 不影響 x,修改 b 會影響 x
a = 100;
std::cout << "修改 a = 100 後: x = " << x << ", a = " << a << " (a 是副本)\n";
b = 200;
std::cout << "修改 b = 200 後: x = " << x << ", b = " << b << " (b 是參考)\n";
std::cout << "\n";
}
// ============================================================
// 第四部分:auto&& — 轉發參考
// ============================================================
void demo_auto_forwarding_ref() {
std::cout << "========================================\n";
std::cout << " auto&& 轉發參考\n";
std::cout << "========================================\n\n";
int x = 42;
const int cx = 100;
auto&& a = x; // int& — x 是左值
auto&& b = 42; // int&& — 42 是右值
auto&& c = cx; // const int& — cx 是 const 左值
auto&& d = std::move(x); // int&& — std::move(x) 是右值
std::cout << "int x = 42; const int cx = 100;\n";
std::cout << "auto&& a = x; -> " << type_name<decltype(a)>() << "\n";
std::cout << "auto&& b = 42; -> " << type_name<decltype(b)>() << "\n";
std::cout << "auto&& c = cx; -> " << type_name<decltype(c)>() << "\n";
std::cout << "auto&& d = std::move(x); -> " << type_name<decltype(d)>() << "\n";
// auto&& 在 range-based for 中非常實用
std::vector<std::string> words = {"hello", "world"};
std::cout << "\n使用 auto&& 遍歷容器(避免不必要的複製):\n";
for (auto&& word : words) {
std::cout << " " << word << " (型別: " << type_name<decltype(word)>() << ")\n";
}
std::cout << "\n";
}
// ============================================================
// 第五部分:auto 與迭代器
// ============================================================
void demo_auto_iterators() {
std::cout << "========================================\n";
std::cout << " auto 與迭代器\n";
std::cout << "========================================\n\n";
std::vector<int> vec = {10, 20, 30, 40, 50};
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
// auto 大幅簡化迭代器的使用
std::cout << "vector 迭代:\n";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << " " << *it;
}
std::cout << "\n\n";
std::cout << "map 迭代(不用 auto 會很冗長):\n";
for (auto it = scores.begin(); it != scores.end(); ++it) {
std::cout << " " << it->first << ": " << it->second << "\n";
}
// C++17 結構化繫結更簡潔
std::cout << "\nC++17 結構化繫結:\n";
for (const auto& [name, score] : scores) {
std::cout << " " << name << ": " << score << "\n";
}
std::cout << "\n";
}
// ============================================================
// 第六部分:auto 與 lambda
// ============================================================
void demo_auto_lambda() {
std::cout << "========================================\n";
std::cout << " auto 與 lambda\n";
std::cout << "========================================\n\n";
// lambda 的型別是匿名的,必須使用 auto
auto add = [](int a, int b) { return a + b; };
auto greet = [](const std::string& name) {
return "你好, " + name + "!";
};
// 泛型 lambda(C++14)
auto generic_add = [](auto a, auto b) { return a + b; };
std::cout << "add(3, 4) = " << add(3, 4) << "\n";
std::cout << greet("小明") << "\n";
std::cout << "generic_add(1, 2) = " << generic_add(1, 2) << "\n";
std::cout << "generic_add(1.5, 2.3) = " << generic_add(1.5, 2.3) << "\n";
std::cout << "generic_add(string, string) = "
<< generic_add(std::string("Hello"), std::string(" World")) << "\n";
std::cout << "\n";
}
// ============================================================
// 第七部分:auto 的陷阱
// ============================================================
void demo_auto_pitfalls() {
std::cout << "========================================\n";
std::cout << " auto 的常見陷阱\n";
std::cout << "========================================\n\n";
// 陷阱 1:大括號初始化
auto x1 = {1, 2, 3}; // std::initializer_list<int>
// auto x2{1}; // C++17: int; C++11/14: initializer_list<int>
std::cout << "auto x1 = {1,2,3}; -> " << type_name<decltype(x1)>() << "\n";
// 陷阱 2:vector<bool> 的代理物件
std::vector<bool> flags = {true, false, true};
auto flag = flags[0]; // 不是 bool!是 vector<bool>::reference 代理物件
std::cout << "auto flag = vector<bool>[0]; -> " << type_name<decltype(flag)>()
<< " (代理物件!)\n";
bool real_flag = flags[0]; // 強制轉換為 bool
std::cout << "bool real_flag = vector<bool>[0]; -> " << type_name<decltype(real_flag)>()
<< " (正確)\n";
// 陷阱 3:不可見的隱式轉換
std::vector<int> vec = {1, 2, 3};
// unsigned int sz = vec.size(); // 可能的型別不匹配警告
auto sz = vec.size(); // 正確取得 size_t
std::cout << "auto sz = vec.size(); -> " << type_name<decltype(sz)>()
<< " (正確的 size_t)\n";
std::cout << "\n";
}
// ============================================================
// 第八部分:decltype 基本用法
// ============================================================
void demo_decltype_basics() {
std::cout << "========================================\n";
std::cout << " decltype 基本用法\n";
std::cout << "========================================\n\n";
int x = 42;
const int cx = x;
const int& rcx = x;
int* px = &x;
// decltype 保留所有修飾
std::cout << "int x = 42;\n";
std::cout << "decltype(x) -> " << type_name<decltype(x)>() << "\n";
std::cout << "decltype(cx) -> " << type_name<decltype(cx)>() << " (保留 const)\n";
std::cout << "decltype(rcx) -> " << type_name<decltype(rcx)>() << " (保留 const&)\n";
std::cout << "decltype(px) -> " << type_name<decltype(px)>() << "\n";
std::cout << "\n";
}
// ============================================================
// 第九部分:decltype 對表達式的規則
// ============================================================
void demo_decltype_expressions() {
std::cout << "========================================\n";
std::cout << " decltype 對表達式的規則\n";
std::cout << "========================================\n\n";
int x = 42;
// 重要差異:變數名 vs 表達式
std::cout << "int x = 42;\n";
std::cout << "decltype(x) -> " << type_name<decltype(x)>()
<< " (變數名,直接取宣告型別)\n";
std::cout << "decltype((x)) -> " << type_name<decltype((x))>()
<< " ((x) 是左值表達式,所以是 int&)\n";
// 更多表達式範例
int a = 1, b = 2;
std::cout << "\ndecltype(a + b) -> " << type_name<decltype(a + b)>()
<< " (加法結果是右值)\n";
std::cout << "decltype(a += b) -> " << type_name<decltype(a += b)>()
<< " (複合賦值結果是左值)\n";
// 條件表達式
bool cond = true;
std::cout << "decltype(cond ? a : b) -> " << type_name<decltype(cond ? a : b)>()
<< " (兩個左值,結果是左值)\n";
std::cout << "\n";
}
// ============================================================
// 第十部分:decltype(auto)
// ============================================================
// 使用 decltype(auto) 完美保留回傳值型別
template<typename Container>
decltype(auto) access_element(Container& c, std::size_t index) {
return c[index]; // 保留 operator[] 的回傳型別(通常是 T&)
}
// 對比:使用 auto(會失去參考語意)
template<typename Container>
auto access_element_auto(Container& c, std::size_t index) {
return c[index]; // 回傳副本,失去參考!
}
void demo_decltype_auto() {
std::cout << "========================================\n";
std::cout << " decltype(auto)\n";
std::cout << "========================================\n\n";
// 變數推導
int x = 42;
decltype(auto) a = x; // int(等同 decltype(x))
decltype(auto) b = (x); // int&(等同 decltype((x)),小心!)
std::cout << "int x = 42;\n";
std::cout << "decltype(auto) a = x; -> " << type_name<decltype(a)>() << "\n";
std::cout << "decltype(auto) b = (x); -> " << type_name<decltype(b)>()
<< " (注意!加括號變成參考)\n\n";
// 函式回傳值比較
std::vector<int> vec = {10, 20, 30};
// decltype(auto) 保留參考,可以修改原始容器
decltype(auto) elem1 = access_element(vec, 0);
elem1 = 999;
std::cout << "使用 decltype(auto) 修改 vec[0]:\n";
std::cout << " vec[0] = " << vec[0] << " (成功修改為 999)\n";
// auto 回傳副本,無法修改原始容器
auto elem2 = access_element_auto(vec, 1);
elem2 = 888;
std::cout << "使用 auto 嘗試修改 vec[1]:\n";
std::cout << " vec[1] = " << vec[1] << " (仍然是 20,因為 auto 回傳副本)\n";
std::cout << " elem2 = " << elem2 << " (只修改了副本)\n";
std::cout << "\n";
}
// ============================================================
// 第十一部分:auto vs decltype 總結比較
// ============================================================
void demo_comparison() {
std::cout << "========================================\n";
std::cout << " auto vs decltype 比較總結\n";
std::cout << "========================================\n\n";
const int x = 42;
const int& rx = x;
std::cout << "const int x = 42; const int& rx = x;\n\n";
std::cout << std::string(50, '-') << "\n";
std::cout << "表達式 | auto | decltype\n";
std::cout << std::string(50, '-') << "\n";
// auto 忽略頂層 const 和參考
auto a1 = x;
auto a2 = rx;
std::cout << "= x | " << type_name<decltype(a1)>()
<< " | " << type_name<decltype(x)>() << "\n";
std::cout << "= rx | " << type_name<decltype(a2)>()
<< " | " << type_name<decltype(rx)>() << "\n";
auto& a3 = x;
std::cout << "auto& / decl | " << type_name<decltype(a3)>()
<< " | (同上)\n";
std::cout << std::string(50, '-') << "\n";
std::cout << "\n關鍵差異:\n";
std::cout << " 1. auto 像模板推導:忽略頂層 const 和參考\n";
std::cout << " 2. decltype 忠實保留所有型別修飾\n";
std::cout << " 3. decltype 對括號表達式會推導為參考\n";
std::cout << " 4. decltype(auto) 結合兩者:auto 的便利 + decltype 的精確\n";
std::cout << "\n";
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << "╔══════════════════════════════════════╗\n";
std::cout << "║ C++17 型別推導:auto 與 decltype ║\n";
std::cout << "╚══════════════════════════════════════╝\n\n";
demo_auto_basics();
demo_auto_const();
demo_auto_reference();
demo_auto_forwarding_ref();
demo_auto_iterators();
demo_auto_lambda();
demo_auto_pitfalls();
demo_decltype_basics();
demo_decltype_expressions();
demo_decltype_auto();
demo_comparison();
std::cout << "=== 程式結束 ===\n";
return 0;
}
Articoli correlati
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Leggi l'articolo →