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

时间:2010-04-13 23:02:43

标签: 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;
} 

定义此功能后,您可以像这样使用它:

#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;
} 

6 个答案:

答案 0 :(得分:11)

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

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

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

答案 1 :(得分:6)

我不是C ++专家,但在我看来,重点是让编译器在test()的两个重载之间做出决定。如果Derived来自Base,那么将使用第一个,返回char,否则将使用第二个 - 返回char[2]sizeof()运算符然后确定发生了哪些操作并相应地设置conversion::exists的值。

答案 2 :(得分:5)

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

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

答案 3 :(得分: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)) }; 
}

e.g:

IsRelated<Base, Derived>::exists

这样你就可以在编译时访问这些信息。

答案 4 :(得分:2)

顺便说一句,您可以使用__is_base_of中引入的“type_traits”中的std::tr1(MSCV 2008编译器具有内在支持)。

答案 5 :(得分:1)

原始代码将构造Derived的对象,它可能会带来意想不到的结果。以下工作可能是另一种选择:

template<typename BaseT, typename CheckT>
inline  bool    isDerived(const CheckT &t){
    char    test(const BaseT   *t);
    char    (&test(...))[2];
    return  (sizeof(test(&t)) == sizeof(char) );
}
相关问题