簡體   English   中英

如何定義采用可變參數 class 模板的 function?

[英]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。 因此,由於SuccessTypeErrorTypes...僅出現在非推導上下文中,因此無法推導它們,並且未明確指定它們的調用將失敗。

您可以看到這條規則是必要的,因為理論上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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM