iT邦幫忙

2025 iThome 鐵人賽

DAY 19
1
Software Development

30 天 Effective C++ 大挑戰!!系列 第 19

[Day 19] Templates and Generic Programming II

  • 分享至 

  • xImage
  •  

又是早起讀書的一天。美好的中午搭配手沖咖啡,休息之餘也來整理筆記吧!

43. Know how to access names in templatized base classes

當呼叫基底函式時,非模板化與模板化的「多型」行為存在差異。其主因在於「完全模板特化」會覆蓋原有的一般模板版本,可能導致編譯器混淆。

完全模板特化為模板的一種特定參數組合提供專屬實現,當前參數與特化匹配時則略過一般模板。例如以下範例:

template<typename Student>
class YoyoScore: public MsgSender<Student> {
public:
    using MsgSender<Student>::doExam;
    void sendScore(const std::string& score) {
        doExam(score);  // complie error here...
    }
};

上述程式碼會編譯失敗。因為某些特化版本中可能未定義 doExam,編譯器無法保證 MsgSender<Student> 中一定存在此函式:

template<>
class MsgSender<Company> {
public:
    void sendName(const std::string& name){}
};

此問題可以透過以下三種方法解決:

  • 加入 using 宣告,明確指定基底類別版本。 e.g. using MsgSender<Student>::sendScore;
  • 使用 this 指標呼叫,解決非模板的查找限制問題。 e.g. this->sendScore(score);
  • 直接指定基類的完全限定名稱,會關閉虛函數的動態綁定故不建議使用。 e.g. MsgSender<Student>::sendScore(score);

C++ 更傾向於在模板定義階段進行早期檢測,因此不對基底類別的模板內容做假設。當模板特化刪除某些函數時,提前發現錯誤有助於在編譯階段就修正問題。

44. Factor parameter-independent code out of templates

模板使用不當容易導致程式碼隱性地膨脹,也就是知識點 30 說的 code bloat 問題。當為不同的型別實例化過多版本時,會讓目標 bin 執行檔變得很大。

例如以下範例,若針對不同的 n 編譯會出現多個重複的函式版本:

template<typename T, std::size_t n>
class SquareMatrix {
public:
    void invert();
};

SquareMatrix<double, 10ul>::invert()
SquareMatrix<double, 5ul>::invert()

透過將與參數無關的邏輯抽離到基類,可以有效減少代碼重複並控制物件檔大小,例如使用私有繼承。這樣 invert 的實作會被集中於基底類別,減少重複的程式碼:

template<typename T>
class SquareMatrixBase {
protected:
    void invert(std::size_t matrixSize);
};

template<typename T, std::size_t n>
class SquareMatrix : private SquareMatrixBase<T> {
public:
    void invert() { this->invert(n); }
};

SquareMatrixBase<double>::invert(unsigned long)
SquareMatrixBetter<double, 10ul>::invert()
SquareMatrixBetter<double, 5ul>::invert()

上一篇
[Day 18] Templates and Generic Programming I
下一篇
[Day 20] Templates and Generic Programming III
系列文
30 天 Effective C++ 大挑戰!!30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言