[英]Variadic templates for multiple heritage assertions - “…redeclared with 3 template parameters…”
我正在嘗試為我的 AVR 編程實現自己的std::is_base_of
(avr-gcc 尚不支持<type_traits>
。我從 cppreference 頁面上的可能實現中獲得靈感,它適用於單一類型檢查。但是,什么我想要實現的是對一個基礎 class 的多種類型的遺產進行靜態執行的有效性檢查。
為簡單起見,我使用std::is_base_of
進行下面的實際檢查,但是我的實際解決方案接近上面鏈接的 cppreference 頁面中的內容。
我將使用它進行標簽調度,更具體地說是允許任何順序的選項標簽。
選項標簽
struct tOption {};
struct tThis : public tOption {};
struct tThat : public tOption {};
struct tElse {}; // Wrongly defined option tag!
單一遺產驗證器結構
template<typename TBase, typename TCandidate>
struct isBaseOf {
isBaseOf() = delete;
static const bool value = std::is_base_of<TBase, TCandidate>::value;
};
static_assert(isBaseOf<tOption, tThat>::value, "Invalid option tag!"); // OK!
static_assert(isBaseOf<tOption, tElse>::value, "Invalid option tag!"); // ERROR! Invalid option tag!
多次檢查的嘗試(除了上面的isBaseOf
聲明)
template<typename TBase, typename TCandidate, typename... TRest>
struct isBaseOf {
isBaseOf() = delete;
static const bool value = isBaseOf<TBase, TRest...>::value &&
std::is_base_of<TBase, TCandidate>::value;
};
這不起作用。 據我所知,我無法使用不同數量的類型重新聲明模板。 但是,我在最后一個模板構造中至少需要兩種類型。 我嘗試將 TBase 作為唯一參數並將值設置為 true,但同樣的問題仍然存在:錯誤:使用 3 個模板參數重新聲明
用法
如前所述,這僅限於單次檢查。 由於我的 class(此處未顯示)對任意數量的選項標簽使用可變參數模板(並且 avr-gcc 不支持完整的 c++14 與constexpr
函數中的 for 循環),我希望能夠使用參數解包並仍然檢查所有選項標簽繼承了我的基本標簽( tOption
)。
template<typename... TOptions>
class tMyClass {
static_assert(isBaseOf<tOption, TOptions...>::value, "Invalid option tag(s)!"); // <--- THIS
// ...
};
使用函數 - 丑陋和不需要的
我使用 function 而不是另一個結構讓它工作,但我認為這很令人困惑。 我寧願有一種方法來解決整個遞歸(靜態)堆棧中的問題。 此外,這迫使我構建每個標簽,這不是很整潔的 IMO。
template<typename TBase, typename TCandidate>
constexpr bool isBaseOf2(const TBase&, const TCandidate&) {
return std::is_base_of<TBase, TCandidate>::value;
}
template<typename TBase, typename TCandidate, typename... TRest>
constexpr bool isBaseOf2(const TBase& base, const TCandidate&, const TRest&... rest) {
return isBaseOf2(base, rest...) && std::is_base_of<TBase, TCandidate>::value;
}
static_assert(isBaseOf2(tOption{}, tThis{}, tThat{}), "Invalid option tag(s)!"); // OK!
static_assert(isBaseOf2(tOption{}, tThis{}, tElse{}), "Invalid option tag(s)!"); // ERROR! Invalid option tag(s)!
有沒有辦法用其他數量的參數重新定義結構模板,例如上面的多次檢查嘗試?
在 c++17 中,您可以在&&
運算符上使用折疊表達式來實現此目的
template<typename Base, typename ...Candidates>
struct is_base_of_multiple {
static constexpr bool value = (std::is_base_of_v<Base, Candidates> && ...); // change std::is_base_of_v to your own implementation
};
如果您不能使用 c++17,但可以使用 c++11,這是另一種僅使用可變參數模板的方法
template <typename Base, typename First, typename ...Rest>
struct is_base_of_multiple {
static constexpr bool value = std::is_base_of<Base, First>::value && is_base_of_multiple<Base, Rest...>::value;
};
template <typename Base, typename Candidate>
struct is_base_of_multiple<Base, Candidate> {
static constexpr bool value = std::is_base_of<Base, Candidate>::value;
};
問題
template<typename TBase, typename TCandidate, typename... TRest>
struct isBaseOf {
isBaseOf() = delete;
static const bool value = isBaseOf<TBase, TRest...>::value &&
std::is_base_of<TBase, TCandidate>::value;
};
就這樣結束了嗎,你完成了:
static const bool value = isBaseOf<TBase, /*Empty Pack*/>::value &&
std::is_base_of<TBase, TCandidate>::value;
isBaseOf<TBase, TRest...>
對於空包無效。
您必須添加專業化來處理這種情況:
template<typename TBase, typename TCandidate>
struct isBaseOf<TBase, TCandidate> {
isBaseOf() = delete;
static const bool value = std::is_base_of<TBase, TCandidate>::value;
};
沒有遞歸的替代方案:
template <bool... Bs> struct Bools{};
template <bool... Bs> using All = std::is_same<Bools<true, Bs...>, Bools<Bs..., true>>;
template<typename TBase, typename... TCandidates>
using isBaseOf = All<std::is_base_of<TBase, TCandidates>::value...>;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.