C++26:更易於使用的 assert() 巨集
C++26 引入了變性參數 assert 巨集,解決了過去因模板或大括號中的逗號導致的編譯錯誤,讓這項基礎工具不再脆弱且更符合直覺。
背景
C++26 預計引入 P2264R7 提案,針對歷史悠久的 assert() 巨集進行改良。由於傳統的巨集預處理器無法正確解析模板角括號或大括號初始化中的逗號,常導致開發者必須額外添加括號才能編譯成功;新提案透過變數參數巨集技術,旨在消除這些語法摩擦,讓斷言工具更符合現代 C++ 的使用習慣。
社群觀點
針對這項改進,Hacker News 社群的反應呈現出實務派與語言純潔派的交鋒。許多開發者認為這項變更雖然微小但確實解決了長期的痛點,特別是解決了巨集命名不符合大寫慣例所帶來的誤導性。然而,不少資深工程師指出,assert() 最核心的問題並不在於語法解析,而是在於其標準實作過於貧乏。有留言者分享了自定義斷言工具的經驗,認為一個理想的斷言應該能自動捕捉並顯示觸發失敗時的變數數值,而非僅僅是終止程式,這在除錯效率上有著天壤之別。
關於斷言的使用哲學,社群內展開了激烈的辯論。部分開發者警告,在斷言中放入具有「副作用」的程式碼是極其危險的行為,因為當程式在發布模式下定義了 NDEBUG 時,這些副作用會神祕消失,導致測試與生產環境行為不一致。對此,有人提出應效仿 Abseil 庫的作法,明確區分保證執行的檢查與僅在開發階段存在的檢查。另一派觀點則主張「攻擊性編程」,建議除非效能壓力極大,否則應在所有版本中保留斷言,以確保程式的正確性優於執行速度。
此外,討論也延伸到了 C++ 語言整體的複雜度。有評論諷刺 C++ 發展至今連字串分割或 Unicode 支援等基礎功能仍未完善,卻在微小的巨集語法上打轉。同時,也有人對預處理器的本質提出質疑,認為與其不斷修補巨集,不如加速推動語言層級的元編程能力,從根本上取代這些過時的文字替換機制。儘管如此,多數人仍認同在合約編程正式普及前,優化現有的 assert() 仍具備實際的工程價值。
延伸閱讀
- Abseil 斷言慣例:Google 開源庫中關於 CHECK 與 DCHECK 的設計規範,用於區分不同環境下的檢查需求。
- Windows.h 的 NOMINMAX 處理:討論中提到 Windows 環境下常見的巨集衝突問題,以及如何透過預處理指令規避。
- C++20 std::views::split:針對留言中提到的字串分割替代方案,雖然功能強大但存在編譯效能與除錯難度的爭議。