C++20中别名模板的模板实参推导指南问题
为别名化类模板实现专属模板实参推导
想要为别名化的类模板推导模板实参,有资料提到C++20支持该特性,但简单别名的推导方法无法适配逻辑更复杂的别名场景,且我们希望仅在使用别名时触发特定推导规则。
简单别名的可行推导示例
对于直接重命名的别名,C++20中可以通过给原类模板添加推导指引实现:
template <typename T> struct Bar { Bar(T); }; template <typename T> using Foo = Bar<T>; template <typename T> Bar(T) -> Bar<T>; // 推导指南 Foo f{42}; // 正确推导为Bar<int>
复杂别名的推导问题
当别名的逻辑更复杂时(如下方BarVec是MyVector<Bar<T>>的别名),直接给别名写推导指引会报错,而给原类模板添加全局推导指引会影响所有原类的使用:
template <typename T> struct MyVector{ MyVector(T); }; template <typename T> struct Bar { Bar(T); }; template <typename T> using BarVec = MyVector<Bar<T>>; // 需求:BarVec(int)推导为MyVector<Bar<int>>,但MyVector(int)仍推导为MyVector<int> // 尝试1:直接给别名写推导指引,编译器报错 template<typename T> BarVec(T) -> BarVec<T>; // 错误:无法为别名模板指定推导指南 // 尝试2:给原类添加推导指引,但会影响所有MyVector的使用 template<typename T> MyVector(T) -> MyVector<Bar<T>>; // 所有MyVector(T)都会生成MyVector<Bar<T>>,不符合需求 BarVec bv{42}; // 期望推导为MyVector<Bar<int>> MyVector mv{42}; // 期望推导为MyVector<int>
解决方案:将别名改为继承式类模板
由于C++20不支持直接给别名模板添加推导指引,我们可以把BarVec从别名改为继承自MyVector<Bar<T>>的类模板,这样就能给它添加专属的推导指引,同时不影响原MyVector的推导行为:
template <typename T> struct MyVector{ MyVector(T); }; template <typename T> struct Bar { Bar(T); }; // 将别名改为继承类模板 template <typename T> struct BarVec : MyVector<Bar<T>> { // 继承原类的构造函数 using MyVector<Bar<T>>::MyVector; }; // 给BarVec添加专属推导指引 template <typename T> BarVec(T) -> BarVec<T>; // 使用验证 BarVec bv{42}; // 正确推导为BarVec<int>,即MyVector<Bar<int>> MyVector mv{42}; // 正确推导为MyVector<int>
替代方案:使用推导辅助函数
如果不想修改别名的定义,可以创建一个推导辅助函数,通过函数模板推导来生成目标类型:
template <typename T> struct MyVector{ MyVector(T); }; template <typename T> struct Bar { Bar(T); }; template <typename T> using BarVec = MyVector<Bar<T>>; // 推导辅助函数 template <typename T> auto make_bar_vec(T&& t) -> BarVec<T> { return BarVec<T>(std::forward<T>(t)); } // 使用验证 auto bv = make_bar_vec(42); // 推导为MyVector<Bar<int>> MyVector mv{42}; // 推导为MyVector<int>
内容的提问来源于stack exchange,提问作者igel
相关产品推荐
相关产品推荐

