![](/img/trans.png)
[英]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.