在C++中编译时间类型确定

dic*_*oce 16 c++ inheritance templates types

一位同事最近向我展示了他在网上找到的一些代码.它似乎允许编译时间确定类型是否与另一种类型具有"是"关系.我认为这非常棒,但我不得不承认我对这实际上是如何运作一无所知.任何人都可以向我解释这个吗?

template<typename BaseT, typename DerivedT>
inline bool isRelated(const DerivedT&)
{
    DerivedT derived();
    char test(const BaseT&); // sizeof(test()) == sizeof(char)
    char (&test(...))[2];    // sizeof(test()) == sizeof(char[2])
    struct conversion 
    { 
        enum { exists = (sizeof(test(derived())) == sizeof(char)) }; 
    };
    return conversion::exists;
} 
Run Code Online (Sandbox Code Playgroud)

定义此函数后,您可以像这样使用它:

#include <iostream>

class base {};
class derived : public base {};
class unrelated {};

int main()
{
    base b;
    derived d;
    unrelated u;

    if( isRelated<base>( b ) )
        std::cout << "b is related to base" << std::endl;

    if( isRelated<base>( d ) )
        std::cout << "d is related to base" << std::endl;

    if( !isRelated<base>( u ) )
        std::cout << "u is not related to base" << std::endl;
} 
Run Code Online (Sandbox Code Playgroud)

SLa*_*aks 11

它声明了两个名为的重载函数test,一个采用a Base和一个采取任何东西(...),并返回不同的类型.

然后它使用a调用该函数Derived并检查其返回类型的大小以查看调用的重载.(它实际上使用返回的函数的返回值调用函数Derived,以避免使用内存)

因为enums是编译时常量,所以这一切都是在编译时在类型系统中完成的.由于函数最终不会在运行时调用,因此它们没有实体并不重要.


EMP*_*EMP 6

我不是C++专家,但在我看来,重点是让编译器在两个重载之间做出决定test().如果DerivedBase从那时得到的话,将使用第一个返回char,否则将使用第二个 - 返回char[2].然后,sizeof()操作员确定发生了这些中的哪一个并相应地设置了值conversion::exists.


Ben*_*igt 5

它非常酷但实际上并不起作用,因为用户定义的转换优先于省略号匹配,而const引用可以绑定用户定义转换的临时结果.所以char*p; is_related<bool>(p);会返回true(在VS2010中测试).

如果要真正测试继承关系,可以采用类似的方法,但使用指针而不是引用.


jon*_*son 5

有什么理由你不会使用这样的东西:

template<typename BaseT, typename DerivedT>
struct IsRelated
{
    static DerivedT derived();
    static char test(const BaseT&); // sizeof(test()) == sizeof(char)
    static char (&test(...))[2];    // sizeof(test()) == sizeof(char[2])

    enum { exists = (sizeof(test(derived())) == sizeof(char)) }; 
}
Run Code Online (Sandbox Code Playgroud)

例如:

IsRelated<Base, Derived>::exists
Run Code Online (Sandbox Code Playgroud)

这样您就可以在编译时访问信息.