具代表性的面試主題

程式設計面試:C++26 參數包索引如何運作,何時應做編譯器降級?

程式題中等
Offer.cc 編輯團隊發佈 更新

題幹

你需要從可變參數模板中讀取第 N 個型別或值,並同時支援尚未實作 C++26 的編譯器。請說明 pack indexing 的語法、限制、失敗模式與降級方案。

題幹與適用場景

一個泛型函式庫要從型別包或函式參數包中讀取固定位置元素,並在 C++26 編譯器使用 pack indexing;舊工具鏈仍需建置。請解釋表達式包索引、型別包索引、索引限制、特性偵測與相容實作。

本題考察語言規則與工程降級,不要求候選人聲稱所有編譯器版本都已支援此特性。

面試官考察點

  • 能否區分表達式包索引與 pack indexing specifier(型別包索引)。
  • 能否說明索引必須是編譯期常數且越界會形成限制或編譯錯誤。
  • 能否用 __cpp_pack_indexing 做能力偵測,而非只猜編譯器名稱。
  • 能否在保持 API 語意下提供遞迴或 tuple 降級實作。

回答前需要釐清的問題

  1. 要索引的是值包、型別包,還是模板參數包?
  2. 索引來自編譯期常數,還是執行期整數?
  3. 支援矩陣包含哪些編譯器、標準模式與 CI 版本?
  4. 越界應在介面限制階段失敗,還是由呼叫方先驗證?
  5. 相容實作是否必須保持相同錯誤訊息與複雜度?

30 秒回答框架

「C++26 pack indexing 允許用常數索引直接選取表達式包元素,型別包則使用 pack indexing specifier。索引必須是編譯期常數,且不能越界;執行期索引仍需陣列、tuple 或分派表。工程上用 __cpp_pack_indexing 偵測能力,支援時走直接語法,舊編譯器走遞迴或 tuple 降級,並用相同限制與測試覆蓋邊界。」

分步驟深入解答

1. 先區分兩種索引形式

表達式包索引從函式參數包取值;型別包索引從型別參數包取型別。兩者都把位置選擇放在模板實例化階段,減少手寫遞迴,但語法位置與後續使用方式不同。

2. 索引必須可在編譯期求值

索引是在非型別模板參數語境中的常數表達式。執行期整數不能直接替代它;若業務真的需要執行期選擇,應把包展開為 tuple、陣列或函式表,再執行執行期索引。

cpp
template <std::size_t I, class... Ts>
using type_at = Ts...[I];

template <std::size_t I, class... Ts>
constexpr decltype(auto) value_at(Ts&&... values) {
  return values...[I];
}

3. 處理越界與空包

空包沒有可索引元素,索引等於或超過包長度也不成立。公共模板應透過 requires 限制保證索引小於包長度,測試覆蓋空包、首元素、末元素與越界呼叫。

4. 使用特性偵測

cppreference 記錄的特性測試巨集是 __cpp_pack_indexing,值為 202311L。程式應同時檢查巨集與標準模式,必要時再做編譯器 CI;不要把單一編譯器版本號當成語言能力唯一依據。

5. 設計舊編譯器降級

未支援 C++26 時,型別包可用遞迴模板或 tuple 的型別選擇工具;值包可先建立 tuple 再用按位置讀取工具。降級路徑要保留相同越界限制,並在 CI 分別編譯兩條路徑。

6. 評估 API 與診斷

直接 pack indexing 讓實作更短,但仍應藏在穩定 API 後。文件說明所需標準模式,錯誤訊息指出索引與包長度;基準測試比較直接語法與降級路徑的編譯時間和產生程式碼,而不是只比較原始碼行數。

高品質示範回答

「我先確認索引目標。C++26 的表達式包索引取值,型別包使用 pack indexing specifier;索引必須是編譯期常數,空包或越界應在限制階段失敗。用 __cpp_pack_indexing 偵測能力,支援工具鏈使用直接語法,舊工具鏈用遞迴、tuple_elementget 保持同一 API。執行期索引不能硬塞進模板語法,應改用 tuple 或分派表。測試覆蓋空包、邊界、越界、兩種標準模式與兩條實作路徑。」

常見錯誤

  • 把執行期整數當模板索引 → 語言要求編譯期常數 → 改用 tuple、陣列或分派表。
  • 只檢查 __cplusplus 特性可能取決於實作狀態 → 檢查 __cpp_pack_indexing 並跑 CI。
  • 不限制越界 → 錯誤落在深層實例化 → 用 requires 提前失敗。
  • 只實作型別包 → 值包呼叫仍需遞迴 → 分別驗證型別與表達式索引。
  • 降級路徑改變語意 → 不同工具鏈行為不一致 → 共用限制、測試與穩定 API。

追問及應對

pack indexing 能解決執行期索引嗎?

不能。它需要編譯期常數;執行期索引應使用 tuple、陣列、函式表或其他執行期分派結構。

為什麼仍需要 requires

語言規則最終會拒絕越界,但明確限制能在介面邊界給出更早、更清楚的診斷,也方便讓降級實作保持相同契約。

遞迴降級一定比較慢嗎?

不一定。執行時程式可能被最佳化為相同結果,但模板實例化深度、編譯時間與診斷品質可能不同,應以支援矩陣與基準驗證,而非憑語法長度判斷。

公開來源

同類題目

相關面試工具

用 Screenshot 處理演算法題

截圖題目後,依序看約束、解法、程式碼、邊界條件和複雜度。

查看工具