【问题标题】:Compile time type determination in C++在 C++ 中编译时间类型确定
【发布时间】:2011-02-07 16:38:42
【问题描述】:

一位同事最近向我展示了他在网上找到的一些代码。它似乎允许编译时确定一个类型是否与另一种类型具有“是”关系。我认为这非常棒,但我不得不承认我对它的实际工作原理一无所知。谁能给我解释一下?

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

【问题讨论】:

  • 这真是太酷了。
  • 如果您对这些内容感兴趣,请获取 Alexandrescus “现代 C++ 设计” 的副本。
  • 我认为到处都是,例如stackoverflow.com/questions/2631585/…。请注意,测试本身发生在编译时,但您在运行时(从函数返回)获得结果,您几乎无法将其用于任何有用的事情。
  • 这是一个巧妙的技巧,但仅用于教育目的。我永远不会在我使用的代码中使用类似的东西,因为通常在好的设计中你不会明确比较类型。
  • ^^ 我可能永远不应该说“从不”。但是,是的。

标签: c++ inheritance templates types


【解决方案1】:

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

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

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

【讨论】:

  • derived() 不是为了节省内存 - 无论如何,sizeof() 表达式在编译时被评估 - 这是一种不需要 Derived 默认构造的方法(即避免使用test(Derived()))。
  • @gf:我的意思不是声明指向 Dervied 的指针。
【解决方案2】:

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

【讨论】:

  • true..它仅基于重载决议。
【解决方案3】:

这很酷,但实际上并不起作用,因为用户定义的转换优于省略号匹配,并且 const 引用可以绑定用户定义的转换的临时结果。所以char*p; is_related&lt;bool&gt;(p); 将返回true(在VS2010 中测试)。

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

【讨论】:

    【解决方案4】:

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

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

    ?

    例如:

    IsRelated<Base, Derived>::exists
    

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        原代码会构造一个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) );
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-21
          • 1970-01-01
          • 2012-03-13
          • 2020-02-07
          • 2016-10-04
          相关资源
          最近更新 更多