简体   繁体   English

如何定义采用可变参数 class 模板的 function?

[英]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.因此,由于SuccessTypeErrorTypes...仅出现在非推导上下文中,因此无法推导它们,并且未明确指定它们的调用将失败。

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.

相关问题 如何定义可变参数 class 模板的成员模板 function - How to define member template function of variadic class template 如何在0可变参数上专门化可变参数模板类? - How do I specialise a variadic template class on 0 variadic arguments? 如何使用可变参数模板在类中定义类型? - How can I use a variadic template to define a type inside the class? 如何定义可变参数模板的参数? - How can I define arguments of variadic template? 如何在可变参数模板类中获取函数指针的参数类型? - How do I get the argument types of a function pointer in a variadic template class? 如何在 SWIG 中包装可变参数模板类的可变参数模板成员函数? - How can I wrap a variadic template member function of a variadic template class in SWIG? 如何 enable_if 具有可变参数模板参数的类? - How do I enable_if a class with variadic template arguments? 如何使用可变参数 arguments 使这个模板专业化成为 class 的朋友? - How do I make this template specialization with variadic arguments a friend of a class? 如何将元组扩展为可变参数模板函数的参数? - How do I expand a tuple into variadic template function's arguments? 如何使用可变参数模板打印出函数的参数? - How do I print out the arguments of a function using a variadic template?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM