[英]How to define member template function of variadic class template
[英]How do I define a function that takes a variadic class template?
我正在尝试定义一个简单的基于变体的 Result 类型别名,有点像穷人的 rust-like Result 类型:
namespace detail {
template <typename SuccessType, typename... ErrorTypes>
struct Result {
using type = std::variant<SuccessType, ErrorTypes...>;
};
template <typename... ErrorTypes>
struct Result<void, ErrorTypes...> {
using type = std::variant<std::monostate, ErrorTypes...>;
};
} // namespace detail
template <typename SuccessType, typename... ErrorTypes>
using Result_t = detail::Result<SuccessType, ErrorTypes...>::type;
即Result_t
只是一个std::variant
,其中第0
个索引是成功的结果,而 rest 是错误结构。
我定义了这个辅助方法来检查结果是否良好:
template <typename SuccessType, typename... ErrorTypes>
inline bool Ok(const Result_t<SuccessType, ErrorTypes...>& r) {
return r.index() == 0;
}
但是当我尝试实例化它时,我得到一个“没有找到匹配的重载 function”:
错误 C2672:“确定”:找不到匹配的重载 function
错误 C2783: 'bool Ok(const detail::Result<SuccessType,ErrorTypes...>::type &)': 无法推断出 'SuccessType' 的模板参数
struct FileError {};
struct BadJson {};
template <typename T>
using Result = Result_t<T, FileError, BadJson>;
Result<void> GetVoid() { return {}; }
TEST(ConfigFileTest, Result) {
auto res = GetVoid();
EXPECT_EQ(res.index(), 0);
bool ok = Ok(res);
EXPECT_TRUE(ok);
}
我究竟做错了什么? 如果我只是将Ok
模板化为template <typename T> Ok(const T& r)
它可以工作,但会使 function 过于笼统。
展开 function 参数中的Result_t
别名后,如下所示:
template <typename SuccessType, typename... ErrorTypes>
bool Ok(const detail::Result<SuccessType, ErrorTypes...>::type& r) {
return r.index() == 0;
}
这里有问题的部分是模板参数位于名称解析运算符::
的左侧。 ::
剩下的所有内容都是非推导上下文,这意味着它不用于推导模板 arguments。 因此,由于SuccessType
和ErrorTypes...
仅出现在非推导上下文中,因此无法推导它们,并且未明确指定它们的调用将失败。
您可以看到这条规则是必要的,因为理论上detail::Result<SuccessType, ErrorTypes...>
的任何特化都可以具有与 arguments 类型匹配的::type
type。 编译器无法检查每种可能的类型组合。
与其尝试给类型取别名,不如让Result
成为一个实际的新类型:
template <typename SuccessType, typename... ErrorTypes>
struct Result {
using variant_type = std::variant<SuccessType, ErrorTypes...>;
variant_type variant;
};
template <typename... ErrorTypes>
struct Result<void, ErrorTypes...> {
using variant_type = std::variant<std::monostate, ErrorTypes...>;
variant_type variant;
};
template <typename SuccessType, typename... ErrorTypes>
bool Ok(const Result<SuccessType, ErrorTypes...>& r) {
return r.variant.index() == 0;
}
或类似的规定。 如果您真的想使用仅使用别名的旧设计,那么 function 不应将嵌套别名作为参数,而是使用实际类型(这可能与设计意图不符):
template <typename T, typename... ErrorTypes>
bool Ok(const std::variant<T, ErrorTypes...>& r) {
return r.index() == 0;
}
(我删除了模板上的内inline
。function 模板上的inline
并没有多大意义。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.