[英]How do I define a function that takes a variadic class template?
I am trying to define a simple variant-based Result type alias, sort of like a poor man's rust-like Result type:我正在尝试定义一个简单的基于变体的 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;
ie a Result_t
is just an std::variant
where the 0
th index is the successful result and the rest are error structs.即Result_t
只是一个std::variant
,其中第0
个索引是成功的结果,而 rest 是错误结构。
I defined this helper method to check if the result is good:我定义了这个辅助方法来检查结果是否良好:
template <typename SuccessType, typename... ErrorTypes>
inline bool Ok(const Result_t<SuccessType, ErrorTypes...>& r) {
return r.index() == 0;
}
But I get a "no matching overloaded function found" when I try to instantiate it:但是当我尝试实例化它时,我得到一个“没有找到匹配的重载 function”:
error C2672: 'Ok': no matching overloaded function found错误 C2672:“确定”:找不到匹配的重载 function
error C2783: 'bool Ok(const detail::Result<SuccessType,ErrorTypes...>::type &)': could not deduce template argument for 'SuccessType'错误 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);
}
What am I doing wrong?我究竟做错了什么? If I just have Ok
be templated like template <typename T> Ok(const T& r)
it works, but makes the function too general.如果我只是将Ok
模板化为template <typename T> Ok(const T& r)
它可以工作,但会使 function 过于笼统。
After expanding the Result_t
alias in the function parameter, it looks like this:展开 function 参数中的Result_t
别名后,如下所示:
template <typename SuccessType, typename... ErrorTypes>
bool Ok(const detail::Result<SuccessType, ErrorTypes...>::type& r) {
return r.index() == 0;
}
The problematic part here is that the template parameters are left of the name resolution operator ::
.这里有问题的部分是模板参数位于名称解析运算符::
的左侧。 Everything left of ::
is a non-deduced context , meaning that it is not used to deduce template arguments. ::
剩下的所有内容都是非推导上下文,这意味着它不用于推导模板 arguments。 So since SuccessType
and ErrorTypes...
appear only in non-deduced context, they cannot be deduced and a call which doesn't explicitly specifies them will fail.因此,由于SuccessType
和ErrorTypes...
仅出现在非推导上下文中,因此无法推导它们,并且未明确指定它们的调用将失败。
You can see that this rule is necessary, because theoretically any specialization of detail::Result<SuccessType, ErrorTypes...>
could have a ::type
that matches the arguments type.您可以看到这条规则是必要的,因为理论上detail::Result<SuccessType, ErrorTypes...>
的任何特化都可以具有与 arguments 类型匹配的::type
type。 There is no way that the compiler can check this for every possible combination of types.编译器无法检查每种可能的类型组合。
Instead of trying to alias types, make Result
an actual new 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;
}
or something along those lines.或类似的规定。 If you really want to use the old design using only aliases, then the function should not take the nested alias as argument, but the actual type instead (which is probably not match the intent of the design):如果您真的想使用仅使用别名的旧设计,那么 function 不应将嵌套别名作为参数,而是使用实际类型(这可能与设计意图不符):
template <typename T, typename... ErrorTypes>
bool Ok(const std::variant<T, ErrorTypes...>& r) {
return r.index() == 0;
}
(I removed the inline
on the templates. inline
on a function template doesn't really make much sense.) (我删除了模板上的内inline
。function 模板上的inline
并没有多大意义。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.