2017-09-13 32 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:读取 –

相关问题