2010-05-20 76 views
4

我想检查typeid是否在编译时与类型名称(即typeid(int),typeid(std :: string)...)一起使用时进行评估。类型名称的typeid总是在编译时在C++中进行评估?

为此,我在循环中重复了两个typeid调用的比较,并在启用优化的情况下对其进行了编译,以查看编译器是否简化了循环(通过查看简化为1us的执行时间而不是160毫秒)。

我得到了奇怪的结果,因为有时编译器会简化代码,有时它不会。我用G ++(我尝试了不同的版本4.x版),这里是程序:

#include <iostream> 
#include <typeinfo> 
#include <time.h> 

class DisplayData {}; 

class RobotDisplay: public DisplayData {}; 
class SensorDisplay: public DisplayData {}; 

class RobotQt {}; 
class SensorQt {}; 

timespec tp1, tp2; 
const int n = 1000000000; 

int main() 
{ 
    int avg = 0; 
    clock_gettime(CLOCK_REALTIME, &tp1); 
    for(int i = 0; i < n; ++i) 
    { 
//  if (typeid(RobotQt) == typeid(RobotDisplay)) // (1) compile time 
//  if (typeid(SensorQt) == typeid(SensorDisplay)) // (2) compile time 
     if (typeid(RobotQt) == typeid(RobotDisplay) || 
      typeid(SensorQt) == typeid(SensorDisplay)) // (3) not compile time ???!!! 
      avg++; 
     else 
      avg--; 
    } 
    clock_gettime(CLOCK_REALTIME, &tp2); 
    std::cout << "time (" << avg << "): " << 
     (tp2.tv_sec-tp1.tv_sec)*1000000000+(tp2.tv_nsec-tp1.tv_nsec) << 
     " ns" << std::endl; 
} 

在这个问题似乎并不清楚,但条件:
- 如果没有涉及继承,没有问题(总是编译时间)
- 如果我只做一个对比,没有问题
- 问题只是只与比较的脱节,如果所有的条款都是假的出现

那么,有什么我没有得到以及typeid是如何工作的(当它与nam一起使用时,总是应该在编译时进行评估es?)或者这可能是评估或优化中的gcc错误?

关于上下文,我将这个问题追溯到这个非常简化的例子,但我的目标是使用带有模板类型的typeid(因为部分功能模板专业化是不可能的)。

感谢您的帮助!

+0

您是否完全基于您的代码执行需要多长时间,还是您有更确切的证明编译器实际输出的内容? – 2010-05-20 20:38:52

+0

你可以设计你的程序而不需要'typeid'吗?一个比较对象类型的程序被认为是一个糟糕的OO程序。 – 2010-05-20 20:49:39

+0

Dennis>是的,但我只是检查了汇编代码,我可以确认在一种情况下,在两个clock_gettime调用之间有6条指令没有跳转,另一条指令有2条跳转指令,包括一个明显的循环。 – cyril42e 2010-05-20 21:10:28

回答

7

我真的不知道你的问题的答案,但如果你用is_same <>元函数而不是typeid你可能会得到更好的结果。即使你没有访问这个元函数,这是很容易写一个:


template < typename T1, typename T2 > 
struct is_same 
{ 
    enum { value = false }; // is_same represents a bool. 
    typedef is_same<T1,T2> type; // to qualify as a metafunction. 
}; 

template < typename T > 
struct is_same 
{ 
    enum { value = true }; 
    typedef is_same<T,T> type; 
}; 
+0

太棒了! 但是我不得不修改一点点的功能才能工作: [模板 结构is_same ] [如果(is_same ::值){}] 并且有boost :: is_same。 非常感谢,我会这样做的! – cyril42e 2010-05-20 20:47:49

2

typeid是运行时类型识别机制,这表明它是有用的一部分:它的主要用途是在运行时识别指向基类的动态类型。当编译时静态地知道类型时,您不需要“识别”它们,因为您已经知道它们是什么。

在这个例子中,在运行时没有任何东西可以识别,但是在编译时结果没有任何用处(typeid不能出现在const-expressions中,这是模板元编程所需的)。

所以我也建议is_same

+0

是的,我同意,我不知道is_same,但这确实是我想要的。谢谢! – cyril42e 2010-05-20 21:12:36

2

对于任何类型的牛逼,如果牛逼是多态的,需要编译器在运行时评估typeid的东西。如果T是非多态的,编译器需要在编译时评估typeid。但是,我无法在C++草案(n3000.pdf)中找到相关参考。

事实上,在我工作的其中一个项目中,这个技巧用于查找在运行时是否一个类是多态的。

template <class T> 
bool isPolymorphic() { 
    bool answer=false; 
    T *t = new T(); 
    typeid(answer=true,*t); 
    delete t; 
    return answer; 
} 

我在几个月前就问过相关问题here

+1

好吧,但是你在对象上使用typeid,而不是类型名称。即使类型是多态的,给定类型名称在编译时完全已知,不是吗? – cyril42e 2010-05-20 21:28:50

+0

做'new' /'delete'而不是只声明一个本地对象的意义是什么? – AnT 2010-05-20 21:31:38

+0

@AndreyT:任何产生'lvalue'的东西都可以用于typeid操作符。我只是为了完整性而从另一个线索回答。 – Abhay 2010-05-21 01:42:38