消除多重繼承的歧義
使用模板基類處理多重繼承時,會出現關於不明確成員函數解析的潛在問題。考慮以下場景:
template
class Base {
public:
template
typename std::enable_if::value>::type foo() {
std::cout 這裡,函數 foo() 僅當模板參數與類型包中的其中一種類型匹配時才可調用。現在,如果派生類別從具有不重疊類型集的多個基底類別繼承,則編譯器在解析 foo() 呼叫時可能會遇到歧義。
struct Derived: public Base,
public Base
{};
在這種情況下,呼叫 Derived().foo() 理想情況下會從 Base 呼叫 foo() 成員函數。然而,GCC 和 Clang 都報告了歧義。
為什麼編譯器無法解決歧義
由於成員函數查找的合併規則而出現編譯錯誤。根據C標準,如果衍生類別本身沒有宣告成員函數,則尋找過程依序搜尋基底類別。然而,如果基類中的聲明集不同,合併就會變得不明確。
在給定的場景中,衍生類別 Derived 沒有明確聲明 foo(),因此編譯器必須合併來自兩個基底類別。由於基底類別包含 foo() 的不同聲明集,因此合併會導致歧義。
解決方案
要解決此歧義,一種選擇是使用 using 聲明在派生類別中明確導入所需的成員函數。但是,這需要用戶添加這些聲明,這對於大型類型清單來說可能很冗長且不切實際。
struct Derived: public Base,
public Base
{
using Base::foo;
using Base::foo;
};
或者,可以使用輔助類別來收集並合併所有基底類別的成員函數,從而允許衍生類別直接存取它們。
template
struct BaseCollector : Bases...
{
using Bases::foo...;
};
struct Derived : BaseCollector , Base>
{};
透過這種方法,使用者不需要添加任何額外的聲明來解決歧義。 BaseCollector 類別有效地合併了所有基底類別的宣告集,使 foo() 函數可用於衍生類別而不會產生歧義。
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3