在模板构建器模式中提取重复的构造函数调用
Great question! Extracting repetitive copy logic into a reusable method is smart, especially as your Builder grows with more template parameters. Let's look at how to avoid manually specifying full template parameter lists in your withT* methods, starting with C11-compatible solutions, then moving to modern C optimizations.
C++11 Solution: Type Traits for Template Parameter Replacement
In C++11, we don't have auto return type deduction or template parameter placeholders, but we can use type traits to automatically inherit unchanged template parameters when replacing one. Here's how:
First, define helper traits to replace specific template parameters of your Builder:
// Helper trait to replace T1 in Builder<T1, T2> template <typename NewT1, typename BuilderType> struct ReplaceT1; // Specialization for our Builder class template <typename NewT1, typename T1, typename T2> struct ReplaceT1<NewT1, Builder<T1, T2>> { using type = Builder<NewT1, T2>; }; // Helper trait to replace T2 in Builder<T1, T2> template <typename NewT2, typename BuilderType> struct ReplaceT2; template <typename NewT2, typename T1, typename T2> struct ReplaceT2<NewT2, Builder<T1, T2>> { using type = Builder<T1, NewT2>; };
Next, update your copy method to return a specified target Builder type:
template <typename TargetBuilder> TargetBuilder copy() { return {param1, param2}; }
Now your withT* methods can use the traits to avoid spelling out all parameters—they only need to specify the new type for the parameter they're changing:
template <typename T1_NEW> typename ReplaceT1<T1_NEW, Builder>::type withT1() { return copy<typename ReplaceT1<T1_NEW, Builder>::type>(); } template <typename T2_NEW> typename ReplaceT2<T2_NEW, Builder>::type withT2() { return copy<typename ReplaceT2<T2_NEW, Builder>::type>(); }
This scales well if you add more template parameters later—just create a new ReplaceTN trait for each, and your withTN methods stay consistent without repeating full template lists.
Modern C++ Optimizations (C14, C17, C++20)
Once you move past C++11, newer language features make this even more concise:
C++14: Auto Return Type Deduction
C++14 allows auto for function return types, which lets us skip explicit type traits in the withT* methods. First, update the copy method to use default template parameters tied to the current Builder's types:
template <typename T1_ = T1, typename T2_ = T2> auto copy() { return Builder<T1_, T2_>{param1, param2}; }
Now your withT* methods become trivial—you only need to specify the new type for the parameter you're changing, and the rest use defaults:
template <typename T1_NEW> auto withT1() { return copy<T1_NEW>(); // T2 defaults to the current Builder's T2 } template <typename T2_NEW> auto withT2() { return copy<T1, T2_NEW>(); // Explicitly keep T1, replace T2 }
C++17: Class Template Argument Deduction (CTAD)
CTAD lets the compiler deduce template parameters for class types from constructor arguments. While it doesn't change the withT* methods much here, it simplifies the copy method's return statement:
template <typename T1_ = T1, typename T2_ = T2> auto copy() { return Builder{param1, param2}; // CTAD deduces Builder<T1_, T2_> }
C++20: Streamlined Syntax
C20 adds std::type_identity (from <type_traits>) to disambiguate template parameters if needed, but the C14 approach already works seamlessly. You could also use concepts to enforce valid template parameters for your Builder, but that's optional depending on your use case.
内容的提问来源于stack exchange,提问作者BeeOnRope

