模板函数参数中模板化结构体的推导问题
问题:不修改main()、ModifyStruct()和StructType,让Ret对象自动适配ModifyStruct参数
原代码
template <typename RetType, typename ResultFlagType> struct Ret { RetType value; ResultFlagType flag; operator RetType() { return value; } operator ResultFlagType() { return flag; } }; template <typename T> struct StructType { T a; float b; char c; }; enum class ResultFlag { Success, Failure, }; template <typename T> Ret<StructType<T>, ResultFlag> BuildStruct(T a, float b, char c) { return { { a, b, c }, ResultFlag::Success }; } template <typename T> Ret<StructType<T>, ResultFlag> ModifyStruct(StructType<T> s) { s.b += 3; return { s, ResultFlag::Success }; } int main() { auto ret = BuildStruct(3, 2.1, 'a'); if (ret == ResultFlag::Success) { ModifyStruct(ret); } }
编译报错
GCC在模板推导阶段会抛出错误:
"Ret<StructType<int>, ResultFlag>' is not derived from 'StructType<T>"
原因是C++模板参数推导不会考虑用户定义的隐式转换——编译器无法从Ret<StructType<int>, ResultFlag>推导出ModifyStruct需要的T,即便Ret有转换为StructType<int>的运算符。
限制条件
禁止修改main()、ModifyStruct()的原定义或struct StructType,需实现自动转换/推导,无需显式类型转换。
可行解决方案
方案1:添加ModifyStruct的重载函数
在不改动原ModifyStruct()的前提下,新增一个重载版本,专门处理Ret类型的参数:
template <typename T> Ret<StructType<T>, ResultFlag> ModifyStruct(const Ret<StructType<T>, ResultFlag>& ret) { // 利用Ret的转换运算符,转发给原函数 return ModifyStruct(static_cast<StructType<T>>(ret)); }
这个重载会让编译器自动推导T,并将Ret对象转换为StructType<T>后调用原函数,完全符合限制条件——原函数、main()和StructType都保持不变。
方案2:修改Ret结构体(允许修改的前提下)
如果可以修改Ret结构体,我们可以优化其转换逻辑,或者添加辅助类型别名帮助编译器识别:
template <typename RetType, typename ResultFlagType> struct Ret { RetType value; ResultFlagType flag; // 保留原有转换运算符 operator RetType() const { return value; } operator ResultFlagType() const { return flag; } // 添加嵌套类型,明确值类型 using value_type = RetType; };
不过单独修改Ret无法直接解决模板推导问题,配合重载方案使用会更稳妥。
内容的提问来源于stack exchange,提问作者Fabiano Raffaelli
相关产品推荐
相关产品推荐

