在 c++ 中,类型名称的 typeid 是否总是在编译时求值?
我想检查 typeid 在与类型名称一起使用时是否在编译时进行评估(即 typeid(int)、typeid(std::string)...)。
为此,我在循环中重复比较两个 typeid 调用,并在启用优化的情况下对其进行编译,以查看编译器是否简化了循环(通过查看执行时间,简化时为 1us,而不是简化时为 160ms)事实并非如此)。
我得到了奇怪的结果,因为有时编译器会简化代码,有时则不会。我使用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 的工作方式,是否有一些我没有得到的东西(当与类型名称一起使用时,它总是应该在编译时进行评估?)或者可能这是评估或优化中的 gcc 错误吗?
关于上下文,我将问题追溯到这个非常简化的示例,但我的目标是将 typeid 与模板类型一起使用(因为部分函数模板专业化是不可能的)。
感谢您的帮助!
I wanted to check that typeid is evaluated at compile time when used with a type name (ie typeid(int), typeid(std::string)...).
To do so, I repeated in a loop the comparison of two typeid calls, and compiled it with optimizations enabled, in order to see if the compiler simplified the loop (by looking at the execution time which is 1us when it simplifies instead of 160ms when it does not).
And I get strange results, because sometimes the compiler simplifies the code, and sometimes it does not. I use g++ (I tried different 4.x versions), and here is the program:
#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;
}
The conditions in which this problem appear are not clear, but:
- if there is no inheritance involved, no problem (always compile time)
- if I do only one comparison, no problem
- the problem only appears only with a disjunction of comparisons if all the terms are false
So is there something I didn't get with how typeid works (is it always supposed to be evaluated at compilation time when used with type names?) or may this be a gcc bug in evaluation or optimization?
About the context, I tracked down the problem to this very simplified example, but my goal is to use typeid with template types (as partial function template specialization is not possible).
Thanks for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我真的不知道你问题的答案,但如果你使用 is_same<>元函数而不是 typeid 你可能会得到更理想的结果。即使您无权访问此元函数,也可以很容易地编写一个元函数:
I don't really know the answer to your question but if you use is_same<> metafunction instead of typeid you might get more desirable results. Even if you don't have access to this metafunction, it is very easy to write one:
typeid
是运行时类型识别机制的一部分,它表明了它的用途:它的主要用途是在运行时识别基类的指针/引用的动态类型。当类型在编译时静态已知时,您不需要“识别”它们,因为您已经知道它们是什么。在示例中,尽管在运行时没有任何可识别的内容,但结果在编译时没有任何用处(
typeid
不能出现在 const 表达式中,而这正是模板所需要的元编程)。因此我也推荐
is_same
typeid
is part of the Run-Time Type Identification mechanism, which suggests what it's useful for: it's main usage is identifying the dynamic type of a pointer/reference to a base class at runtime. When the types are statically known at compile-time, you don't need to "identify" them as you already know what they are.In the example, there is nothing to identify at runtime, though, yet the results are not in any way useful at compile-time (
typeid
cannot appear in const-expressions, which is what you need for template metaprogramming).Therefore I also recommend
is_same
对于任何类型 T,如果 T 是多态的,则编译器需要在运行时评估 typeid 内容。如果 T 是非多态的,则编译器需要在编译时评估 typeid 内容。但是,我在 C++ 草案(n3000.pdf)中找不到相关参考资料。
事实上,在我从事的一个项目中,这个技巧被用来确定一个类在运行时是否是多态的。
几个月前,我在此处提出了一个相关问题。
For any type T, if T is polymorphic, the compiler is required to evaluate the typeid stuff at runtime. If T is non-polymorphic, the compiler is required to evaluate the typeid stuff at compile time. However, i cannot find the relevant reference in the C++ draft (n3000.pdf) for it.
Infact, in one of the projects that i worked on, this trick was used to find whether a class was polymorphic at runtime.
I had asked a related question here on SO a few months back.