如何实现无需显式指定模板参数的std::optional版转换函数?
问题描述
现有一个模板转换函数,签名如下:
template<typename In, typename Out> bool Convert(const In& p_in, Out& p_out); // 转换成功返回true,失败返回false。
现在想改成用std::optional的版本,同时调换了模板参数顺序:
template<typename Out, typename In> std::optional<Out> Convert(const In& p_in);
但这里有个问题:Out是返回值类型,编译器没法自动推导它,调用时必须显式指定模板参数才能编译通过,直接调用会因为推导不出Out报错。
如果用auto当返回值,虽然不用显式指定模板参数,但函数签名失去了可读性,得看实现才知道返回的是std::optional<Out>。
有没有办法既能保留std::optional<Out>这种清晰的函数签名,又能在调用时不用显式指定模板参数?
解决方案
可以通过以下几种方法实现需求:
1. 自定义类型标签重载
定义一个空的标签类,用来传递目标类型信息,核心函数保持清晰签名:
template<typename T> struct TypeTag {}; // 核心转换函数,签名清晰明了 template<typename Out, typename In> std::optional<Out> Convert(const In& p_in) { // 这里写你的转换逻辑:成功返回std::optional<Out>{目标值},失败返回std::nullopt } // 辅助重载,通过标签推导Out类型 template<typename Out, typename In> std::optional<Out> Convert(TypeTag<Out>, const In& p_in) { return Convert<Out, In>(p_in); }
调用的时候只需要传个标签就行,不用显式指定模板参数:
auto result = Convert(TypeTag<MyOutType>{}, my_in_value);
2. 用C++20的std::type_identity简化标签
如果用C++20及以上,可以直接用标准库的std::type_identity,省得自己写标签类:
#include <type_traits> template<typename Out, typename In> std::optional<Out> Convert(const In& p_in) { // 转换逻辑 } template<typename Out, typename In> std::optional<Out> Convert(std::type_identity<Out>, const In& p_in) { return Convert<Out, In>(p_in); }
调用方式:
auto result = Convert(std::type_identity<MyOutType>{}, my_in_value);
3. 带哑元指针的辅助函数
用一个目标类型的哑元指针来推导Out,核心函数保持清晰签名:
// 主转换函数,签名清晰,供需要明确返回类型的场景查看 template<typename Out, typename In> std::optional<Out> ConvertImpl(const In& p_in) { // 转换逻辑 } // 辅助函数,通过哑元指针推导Out,返回值自动推导 template<typename Out, typename In> auto Convert(Out*, const In& p_in) { return ConvertImpl<Out, In>(p_in); }
调用时可以传空指针:
// 写法1:先声明哑元指针 MyOutType* dummy = nullptr; auto result = Convert(dummy, my_in_value); // 写法2:直接用static_cast生成空指针 auto result = Convert(static_cast<MyOutType*>(nullptr), my_in_value);
这种方式下,主函数ConvertImpl保留了std::optional<Out>的清晰签名,辅助函数Convert让调用不用显式指定模板参数,用户也能通过主函数明确知道返回类型。
内容的提问来源于stack exchange,提问作者BobMorane
相关产品推荐
相关产品推荐

