2017-09-13 30 views
35

我需要一個類型特徵,如果給定的類型來自任何東西,那麼這個類型特徵將爲true,否則爲false。使用C++ 17可以檢測結構/類是否有任何基數?

例如:

template<class T> 
struct is_inherit 
    //... logic of inheritance detection 
    ; 

template<class T> 
void AppLogic(){ 
    if constexpr(is_inherit<T>::value) { 
     puts("T has base"); 
     //... 
    } else { 
     puts("T doesn't have base"); 
     //... 
    } 
} 

struct A {}; 
struct C {}; 
struct B: C {}; 

int main() { 
    AppLogic<A>(); // print: T doesn't have base 
    AppLogic<B>(); // print: T has base 
} 

是否有可能以某種方式實現一個 「is_inherit」 特質結構?


爲什麼?

我正在爲Windows x64開發一個手動堆棧框架生成器。根據https://docs.microsoft.com/en-us/cpp/build/return-values-cpp文檔,如果類型:

  • 的長度爲1,2,4,8,16,32或64位;
  • 沒有用戶定義的構造函數,析構函數或複製賦值運算符;
  • 沒有私人或受保護的非靜態數據成員;
  • 沒有引用類型的非靜態數據成員;
  • 沒有基類;
  • 沒有虛擬功能;
  • 並且沒有數據成員也不符合這些要求;

那麼它的返回值是在RAX寄存器中,否則函數 有一個隱藏的參數,我必須檢測和處理。

過去,這是一個C++ 03 POD的定義,但在C++ 11這個改變:

因爲定義在C++ 11的標準已經改變,我們不建議使用std::is_pod進行此測試。

到目前爲止,有些共軛性狀可以檢測出類型是否符合C++ 03 POD的定義。然而,在C++ 17中,聚合規則已經發生了變化,這打破了我的解決方案。

如果我能以某種方式檢測類型T是否有任何基類,我的解決方案將再次工作。

+0

如果它的基數*一般*?不要以爲你沒有「作弊」就可以做到這一點。 – StoryTeller

+1

您需要等待將自省添加到C++中,或查找編譯器特定的技巧。否則我認爲你不能這樣做。但正如維托裏奧羅密歐所說,這可能是一個XY問題。你爲什麼需要這個?可能有更好的方法來解決你原來的問題。 – bolov

+0

是的,一般來說,檢測給定的類型有任何基地,不喜歡std :: is_base_of在那裏我必須給2種類型和特質返回是X繼承Y. – Nyufu

回答

31

是的,這是可能的,至少對於聚合。

首先,我們建造一個類模板可轉化爲它的模板參數的任何合適的基極:

template<class T> 
struct any_base { 
    operator T() = delete; 
    template<class U, class = std::enable_if_t<std::is_base_of_v<U, T>>> operator U(); 
}; 

然後,我們檢測模板參數T是否是骨料constructible從any_base<T>類型的值:

template<class, class = void> struct has_any_base : std::false_type {}; 
template<class T> 
struct has_any_base<T, std::void_t<decltype(T{any_base<T>{}})>> : std::true_type {}; 

Example

+4

問題if我有一個類,比如'class E {E(B&){}};'我害怕has_any_base_v會說真的 – gu1d0

+1

@ gu1d0哦,是的,我忘記了'std :: is_base_of'說類是它自己的基類。謝謝! – ecatmur

+0

@ gu1d0是的,但如果E有任何構造函數,那麼它不是微不足道的,因此不是聚合。ecatmur寫這個解決方案的作品「至少爲聚合」。這將是我的C的一部分++ 03 POD檢測特徵,因此這個解決方案對我來說已經足夠了。 'template struct is_cpp03_pod:std :: bool_constant && std :: is_aggregate_v &&!has_any_base_v > {};' – Nyufu

8

我認爲檢查「T是否源於任何東西」是不可能的,至少不是以符合標準的方式。如果你正在使用這種技術來檢查類型是否是一個POD /瑣碎/骨料,也有一些類型的特點,可以幫助你:

+0

std :: is_base_of –

+1

@Dúthomhas:讀取 –

相關問題