如何用模板推导指南让std::expected支持return {1,2}式返回?
问题分析与解决方案
先根据你的描述还原核心代码场景:
#include <expected> #include <string> struct s { int a; int b; }; // 你希望编译通过的目标函数 std::expected<s, std::string> Func0() { return {1, 2}; // 当前编译失败 } // 双层大括号可正常编译 std::expected<s, std::string> Func1() { return {{1, 2}}; } // 先构造s对象可正常编译 std::expected<s, std::string> Func2() { return s{1, 2}; }
为什么return {1,2}编译失败?
直接返回{1,2}时,编译器会尝试用两个int值直接构造std::expected<s, std::string>,但std::expected没有提供接受两个int参数的构造函数。而双层大括号{{1,2}}的逻辑是:内层大括号先构造s对象,再将这个s传给std::expected的成功值构造函数(接受T&&的模板构造函数),因此可以编译通过。
推导指南在这里不可行
你尝试的推导指南expected(int, int) -> expected<int, int>;完全不匹配需求——它是用来推导构造std::expected<int, int>的场景,和你要的std::expected<s, std::string>无关。更关键的是:Func0的返回类型已经明确是std::expected<s, std::string>,不存在类模板参数推导(CTAD)的过程,推导指南的作用是在你未显式指定类模板参数时(比如直接写expected e{...};)推导模板类型,无法解决返回列表的构造匹配问题。
可行的解决方案
方案1:保留显式构造s的写法(即Func2的方式)
这种写法清晰直接,不需要额外代码,唯一代价是多写一个s类型名。
方案2:编写make_expected辅助函数
类似标准库的make_pair/make_shared,通过参数转发自动构造目标类型并包装成std::expected:
#include <utility> // 用于std::forward template<class T, class... Args> constexpr std::expected<T, std::string> make_expected(Args&&... args) { return std::expected<T, std::string>(T{std::forward<Args>(args)...}); } // 使用方式 std::expected<s, std::string> Func0() { return make_expected<s>(1, 2); }
如果需要支持自定义错误类型,可以把错误类型也作为模板参数:
template<class T, class E = std::string, class... Args> constexpr std::expected<T, E> make_expected(Args&&... args) { return std::expected<T, E>(T{std::forward<Args>(args)...}); }
内容的提问来源于stack exchange,提问作者Philippe Sanche
相关产品推荐
相关产品推荐

