當模板擁有多個帶默認值的類型參數時,指定中間某個參數需顯式提供所有前置參數。命名參數技術通過「修改器」類實現 `Template
template<typename P1=D1, typename P2=D2, typename P3=D3, typename P4=D4>
class BreadSlicer {};
// 想只指定 P3=Custom,不得不寫:
BreadSlicer<D1, D2, Custom> // 麻誤且易錯
// 1. 默認策略
struct DefaultPolicies {
using P1 = DefaultPolicy1;
using P2 = DefaultPolicy2;
using P3 = DefaultPolicy3;
using P4 = DefaultPolicy4;
};
// 2. 修改器 (虛繼承避免菱形衝突)
template<typename Policy> struct Param1_is : virtual DefaultPolicies { using P1 = Policy; };
template<typename Policy> struct Param2_is : virtual DefaultPolicies { using P2 = Policy; };
template<typename Policy> struct Param3_is : virtual DefaultPolicies { using P3 = Policy; };
template<typename Policy> struct Param4_is : virtual DefaultPolicies { using P4 = Policy; };
// 3. 默認參數佔位
struct DefaultPolicyArgs : virtual DefaultPolicies {};
// 4. 標籤區分同類基類
template<typename Base, int Tag> struct Tagged : Base {};
// 5. 選擇器 (四重虛繼承)
template<typename T1, typename T2, typename T3, typename T4>
struct Selector : Tagged<T1,1>, Tagged<T2,2>, Tagged<T3,3>, Tagged<T4,4> {};
// 6. 主模板
template<typename S1=DefaultPolicyArgs, typename S2=DefaultPolicyArgs,
typename S3=DefaultPolicyArgs, typename S4=DefaultPolicyArgs>
class BreadSlicer {
using Policies = Selector<S1,S2,S3,S4>;
public:
void usePolicy3() { typename Policies::P3 p; p.execute(); }
};
// 使用
struct CustomPolicy3 { void execute() { cout << "Custom3\n"; } };
BreadSlicer<Param3_is<CustomPolicy3>> slicer; // 僅指定 P3
slicer.usePolicy3(); // 輸出 Custom3
| 優點 | 缺點 |
|---|---|
| 調用處可讀性極強,參數名自文檔化 | 模板定義複雜,涉及虛繼承、標籤、多重繼承 |
| 順序無關,隨意組合指定參數 | 編譯器錯誤信息難讀 |
| 類型安全,編譯期檢查 | 不支援非類型模板參數 |
命名模板參數是模板元編程中解決「參數列表爆炸」的經典技巧,雖實現繁瑣,但極大提升了庫接口的易用性。理解其虛繼承+標籤+修改器的組合機制,有助於掌握 C++ 類型系統的高級應用。