Série: C++
cpp
492 linhas
· Atualizado 2026-04-03
if_init_statements.cpp
C++/Part4_現代CPP/Ch20_CPP17特性精選/if_init_statements.cpp
// Ch20 範例:if 初始化語句、if constexpr、屬性、string_view
// 編譯:g++ -std=c++17 -Wall -o if_init_statements if_init_statements.cpp
#include <iostream>
#include <string>
#include <string_view>
#include <map>
#include <vector>
#include <optional>
#include <type_traits>
#include <cmath>
#include <algorithm>
#include <mutex>
// ============================================================
// 輔助函式
// ============================================================
void printSeparator(const std::string& title) {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << title << "\n";
std::cout << std::string(60, '=') << "\n";
}
void printSubSection(const std::string& title) {
std::cout << "\n" << std::string(50, '-') << "\n";
std::cout << title << "\n";
std::cout << std::string(50, '-') << "\n";
}
// ============================================================
// Part 1: [[nodiscard]] 屬性範例
// ============================================================
// 標記回傳值不可忽略
[[nodiscard]] int computeChecksum(const std::string& data) {
int sum = 0;
for (char c : data)
sum += static_cast<int>(c);
return sum % 256;
}
// 可以標記在類別/結構上(C++17 擴展)
struct [[nodiscard]] ErrorCode {
int code;
std::string message;
};
ErrorCode validateInput(int value) {
if (value < 0)
return {-1, "值不可為負數"};
if (value > 1000)
return {-2, "值超出範圍"};
return {0, "OK"};
}
// ============================================================
// Part 2: if constexpr 模板範例
// ============================================================
// 根據型別在編譯期選擇不同的處理方式
template <typename T>
std::string typeToString(const T& value) {
if constexpr (std::is_integral_v<T>) {
return "整數:" + std::to_string(value);
} else if constexpr (std::is_floating_point_v<T>) {
return "浮點數:" + std::to_string(value);
} else if constexpr (std::is_same_v<T, std::string>) {
return "字串:\"" + value + "\"";
} else if constexpr (std::is_same_v<T, const char*>) {
return "C 字串:\"" + std::string(value) + "\"";
} else if constexpr (std::is_same_v<T, bool>) {
return value ? "布林:true" : "布林:false";
} else {
return "未知型別";
}
}
// 通用的 print 函式,根據型別自動選擇格式
template <typename T>
void smartPrint(const T& value) {
if constexpr (std::is_arithmetic_v<T>) {
std::cout << "[數值] " << value << "\n";
} else if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
std::cout << "[字串] \"" << value << "\" (長度: " << value.size() << ")\n";
} else if constexpr (std::is_pointer_v<T>) {
if (value)
std::cout << "[指標] " << static_cast<const void*>(value) << "\n";
else
std::cout << "[指標] nullptr\n";
} else {
std::cout << "[物件] (無法直接印出)\n";
}
}
// 安全地取得容器中的元素
template <typename Container>
auto getElement(const Container& c, size_t index)
-> std::optional<typename Container::value_type>
{
if (index < c.size()) {
auto it = c.begin();
std::advance(it, static_cast<long>(index));
return *it;
}
return std::nullopt;
}
// ============================================================
// Part 3: 可變參數模板 + fold expression
// ============================================================
// 使用折疊表達式列印所有引數
template <typename... Args>
void printAll(const Args&... args) {
((std::cout << args << " "), ...);
std::cout << "\n";
}
// 計算所有引數的總和
template <typename... Args>
auto sum(Args... args) {
return (... + args);
}
// 檢查是否所有引數都符合條件
template <typename... Args>
bool allPositive(Args... args) {
return (... && (args > 0));
}
// ============================================================
// Part 4: string_view 相關函式
// ============================================================
// 使用 string_view 避免不必要的拷貝
void analyzeString(std::string_view sv) {
std::cout << " 內容:\"" << sv << "\"\n";
std::cout << " 長度:" << sv.size() << "\n";
std::cout << " 空?" << std::boolalpha << sv.empty() << "\n";
if (!sv.empty()) {
std::cout << " 第一個字元:'" << sv.front() << "'\n";
std::cout << " 最後一個字元:'" << sv.back() << "'\n";
}
}
// string_view 可以接受多種字串來源
size_t countChar(std::string_view sv, char ch) {
size_t count = 0;
for (char c : sv)
if (c == ch) ++count;
return count;
}
bool startsWith(std::string_view sv, std::string_view prefix) {
return sv.size() >= prefix.size() &&
sv.substr(0, prefix.size()) == prefix;
}
bool endsWith(std::string_view sv, std::string_view suffix) {
return sv.size() >= suffix.size() &&
sv.substr(sv.size() - suffix.size()) == suffix;
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << std::string(60, '=') << "\n";
std::cout << "C++17:if 初始化、if constexpr、屬性、string_view\n";
std::cout << std::string(60, '=') << "\n";
// =====================================================
// Part 1: if 帶初始化語句
// =====================================================
printSeparator("Part 1: if / switch 帶初始化語句");
// --- 1.1 if with initializer ---
printSubSection("1.1 if 帶初始化");
std::map<std::string, int> inventory = {
{"蘋果", 50}, {"香蕉", 30}, {"橘子", 25}
};
// C++17 語法:if (初始化; 條件)
// it 的作用域限制在 if-else 區塊內
if (auto it = inventory.find("蘋果"); it != inventory.end()) {
std::cout << "找到蘋果,庫存:" << it->second << "\n";
} else {
std::cout << "未找到蘋果\n";
}
if (auto it = inventory.find("西瓜"); it != inventory.end()) {
std::cout << "找到西瓜,庫存:" << it->second << "\n";
} else {
std::cout << "未找到西瓜\n";
}
// 搭配 insert 的回傳值
if (auto [it, inserted] = inventory.insert({"芒果", 15}); inserted) {
std::cout << "成功新增:" << it->first << " = " << it->second << "\n";
} else {
std::cout << it->first << " 已存在,庫存:" << it->second << "\n";
}
// 搭配 std::optional
auto findFruit = [&](const std::string& name) -> std::optional<int> {
if (auto it = inventory.find(name); it != inventory.end())
return it->second;
return std::nullopt;
};
if (auto qty = findFruit("香蕉"); qty.has_value()) {
std::cout << "香蕉庫存:" << *qty << "\n";
}
// --- 1.2 switch with initializer ---
printSubSection("1.2 switch 帶初始化");
auto getGrade = [](int score) -> char {
// switch (初始化; 條件)
switch (char grade = (score >= 90) ? 'A' :
(score >= 80) ? 'B' :
(score >= 70) ? 'C' :
(score >= 60) ? 'D' : 'F'; grade) {
case 'A': std::cout << score << " 分 → 等級 A(優秀)\n"; break;
case 'B': std::cout << score << " 分 → 等級 B(良好)\n"; break;
case 'C': std::cout << score << " 分 → 等級 C(普通)\n"; break;
case 'D': std::cout << score << " 分 → 等級 D(及格)\n"; break;
case 'F': std::cout << score << " 分 → 等級 F(不及格)\n"; break;
}
return ' ';
};
getGrade(95);
getGrade(82);
getGrade(71);
getGrade(55);
// 搭配 mutex(實際應用場景)
{
std::mutex mtx;
int sharedData = 42;
// lock_guard 的作用域精確限制在 if 區塊內
if (std::lock_guard lock(mtx); sharedData > 0) {
std::cout << "\n鎖定後讀取共享資料:" << sharedData << "\n";
}
// lock_guard 在此自動釋放
}
// =====================================================
// Part 2: if constexpr
// =====================================================
printSeparator("Part 2: if constexpr 編譯期分支");
printSubSection("2.1 型別轉字串");
std::cout << typeToString(42) << "\n";
std::cout << typeToString(3.14) << "\n";
std::cout << typeToString(std::string("Hello")) << "\n";
std::cout << typeToString("World") << "\n";
printSubSection("2.2 智慧列印");
smartPrint(42);
smartPrint(3.14159);
smartPrint(std::string("Modern C++"));
int x = 10;
smartPrint(&x);
int* nullp = nullptr;
smartPrint(nullp);
printSubSection("2.3 通用容器存取");
std::vector<int> vec = {10, 20, 30, 40, 50};
auto e1 = getElement(vec, 2);
auto e2 = getElement(vec, 10);
std::cout << "vec[2] = " << (e1 ? std::to_string(*e1) : "超出範圍") << "\n";
std::cout << "vec[10] = " << (e2 ? std::to_string(*e2) : "超出範圍") << "\n";
// =====================================================
// Part 3: 屬性(Attributes)
// =====================================================
printSeparator("Part 3: C++17 屬性");
// --- [[nodiscard]] ---
printSubSection("3.1 [[nodiscard]]");
auto checksum = computeChecksum("Hello C++17");
std::cout << "校驗碼:" << checksum << "\n";
// 如果取消以下注解,編譯器會發出警告
// computeChecksum("test"); // ⚠️ 忽略了 [[nodiscard]] 回傳值
auto err = validateInput(-5);
std::cout << "驗證結果:code=" << err.code << ", msg=" << err.message << "\n";
// validateInput(42); // ⚠️ 忽略了 [[nodiscard]] 結構的回傳值
// --- [[maybe_unused]] ---
printSubSection("3.2 [[maybe_unused]]");
[[maybe_unused]] int debugLevel = 3; // 不會產生「未使用變數」警告
[[maybe_unused]] bool verbose = true;
// 在函式參數中使用
auto process = []([[maybe_unused]] int reserved, int value) {
return value * 2;
};
std::cout << "process(0, 21) = " << process(0, 21) << "\n";
// --- [[fallthrough]] ---
printSubSection("3.3 [[fallthrough]]");
auto describeMonth = [](int month) {
std::cout << month << " 月 → ";
switch (month) {
case 12:
case 1:
case 2:
std::cout << "冬季";
break;
case 3:
case 4:
case 5:
std::cout << "春季";
break;
case 6:
std::cout << "夏季(開始)";
[[fallthrough]]; // 明確表示要貫穿到下一個 case
case 7:
case 8:
std::cout << "夏季";
break;
case 9:
case 10:
case 11:
std::cout << "秋季";
break;
default:
std::cout << "無效月份";
}
std::cout << "\n";
};
for (int m = 1; m <= 12; ++m) {
describeMonth(m);
}
// =====================================================
// Part 4: 折疊表達式(Fold Expressions)
// =====================================================
printSeparator("Part 4: 折疊表達式");
printSubSection("4.1 printAll — 列印所有引數");
printAll(1, 2.5, "hello", std::string("world"), 'A');
printSubSection("4.2 sum — 計算總和");
std::cout << "sum(1,2,3,4,5) = " << sum(1, 2, 3, 4, 5) << "\n";
std::cout << "sum(1.1, 2.2, 3.3) = " << sum(1.1, 2.2, 3.3) << "\n";
printSubSection("4.3 allPositive — 條件折疊");
std::cout << "allPositive(1,2,3) = " << std::boolalpha
<< allPositive(1, 2, 3) << "\n";
std::cout << "allPositive(1,-2,3) = "
<< allPositive(1, -2, 3) << "\n";
// =====================================================
// Part 5: std::string_view
// =====================================================
printSeparator("Part 5: std::string_view");
// --- 基本建構 ---
printSubSection("5.1 建構 string_view");
// 從字串字面值建構(不配置記憶體)
std::string_view sv1 = "Hello, string_view!";
std::cout << "從字面值:\"" << sv1 << "\"\n";
// 從 std::string 建構
std::string str = "This is a std::string";
std::string_view sv2 = str;
std::cout << "從 std::string:\"" << sv2 << "\"\n";
// 指定長度
std::string_view sv3{"Hello, World!", 5};
std::cout << "指定長度 5:\"" << sv3 << "\"\n\n";
// --- 零拷貝子字串 ---
printSubSection("5.2 零拷貝子字串(substr)");
std::string_view fullPath = "/home/user/documents/report.txt";
std::cout << "完整路徑:\"" << fullPath << "\"\n";
// substr 回傳的也是 string_view,不會配置新記憶體
auto dir = fullPath.substr(0, fullPath.rfind('/'));
auto filename = fullPath.substr(fullPath.rfind('/') + 1);
std::cout << "目錄:\"" << dir << "\"\n";
std::cout << "檔名:\"" << filename << "\"\n";
// remove_prefix / remove_suffix
std::string_view greeting = ">>>Hello<<<";
greeting.remove_prefix(3); // 移除前 3 個字元
greeting.remove_suffix(3); // 移除後 3 個字元
std::cout << "修剪後:\"" << greeting << "\"\n\n";
// --- 分析字串 ---
printSubSection("5.3 字串分析函式");
// 同一個函式可以接受 const char*、string、string_view
analyzeString("Hello from const char*");
std::cout << "\n";
std::string s = "Hello from std::string";
analyzeString(s);
std::cout << "\n";
std::string_view sv = "Hello from string_view";
analyzeString(sv);
// --- 字元計數與前後綴 ---
printSubSection("5.4 實用函式");
std::string text = "C++ is a powerful programming language";
std::cout << "文字:\"" << text << "\"\n";
std::cout << "空格數量:" << countChar(text, ' ') << "\n";
std::cout << "字母 a 數量:" << countChar(text, 'a') << "\n";
std::cout << "以 'C++' 開頭?" << std::boolalpha << startsWith(text, "C++") << "\n";
std::cout << "以 'Java' 開頭?" << startsWith(text, "Java") << "\n";
std::cout << "以 'language' 結尾?" << endsWith(text, "language") << "\n";
// --- 比較 ---
printSubSection("5.5 比較操作");
std::string_view a = "apple";
std::string_view b = "banana";
std::string_view c = "apple";
std::cout << "\"" << a << "\" == \"" << c << "\"?" << (a == c) << "\n";
std::cout << "\"" << a << "\" == \"" << b << "\"?" << (a == b) << "\n";
std::cout << "\"" << a << "\" < \"" << b << "\"?" << (a < b) << "\n";
// 可以直接與 std::string 和 const char* 比較
std::string strApple = "apple";
std::cout << "string_view 與 std::string 比較:" << (a == strApple) << "\n";
// --- string_view 的注意事項 ---
printSubSection("5.6 注意事項");
std::cout << "⚠️ string_view 不保證以 null 結尾\n";
std::cout << "⚠️ 不要用 string_view 持有臨時字串的參考\n";
std::cout << "⚠️ string_view 不擁有資料,底層字串必須保持有效\n";
std::cout << "\n";
// 錯誤示範(概念說明,不要這樣做)
std::cout << "正確用法:\n";
std::cout << " ✅ void func(std::string_view sv) { ... }\n";
std::cout << " ✅ 函式參數使用 string_view 取代 const string&\n";
std::cout << " ❌ std::string_view sv = getString(); // 如果回傳臨時 string\n";
std::cout << " ❌ 儲存 string_view 為類別成員(除非確定生命週期)\n";
// =====================================================
// 總結
// =====================================================
printSeparator("總結");
std::cout << R"(
C++17 為日常程式設計帶來了許多便利的改進:
if/switch 帶初始化:
• 將變數作用域限制在分支區塊內
• 讓程式碼更簡潔、更安全
if constexpr:
• 編譯期分支判斷
• 取代 SFINAE 和 tag dispatch 的部分場景
• 讓模板程式碼更直觀
屬性:
• [[nodiscard]] — 防止忽略重要的回傳值
• [[maybe_unused]] — 消除未使用變數的警告
• [[fallthrough]] — 明確標記 switch 貫穿
std::string_view:
• 零拷貝的字串檢視
• 適合用於函式參數
• 注意生命週期管理
)";
return 0;
}
Artigos relacionados
C++
c
Atualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Ler artigo →
C++
c
Atualizado 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Ler artigo →
C++
cpp
Atualizado 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Ler artigo →
C++
c
Atualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Ler artigo →
C++
c
Atualizado 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Ler artigo →
C++
cpp
Atualizado 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Ler artigo →