在我正在做的一个项目中,我看到了以下代码
struct Base {
virtual ~Base() { }
};
struct ClassX {
bool isHoldingDerivedObj() const {
return typeid(1 ? *m_basePtr : *m_basePtr) == typeid(Derived);
}
Base *m_basePtr;
};我从未见过typeid被这样使用过。为什么它要和?:跳这种奇怪的舞,而不是只跳typeid(*m_basePtr)?
编辑:在这段代码的另一个地方,我看到了这个,它看起来等同于“多余的”。
template<typename T> T &nonnull(T &t) { return t; }
struct ClassY {
bool isHoldingDerivedObj() const {
return typeid(nonnull(*m_basePtr)) == typeid(Derived);
}
Base *m_basePtr;
};发布于 2011-07-23 04:59:43
我能看到的唯一效果是,1 ? X : X将X作为右值,而不是普通的X,后者将是左值。对于像数组(衰减到指针)这样的东西,这对typeid()来说可能很重要,但我认为如果知道Derived是一个类,那就不重要了。也许它是从某个有价值的地方复制过来的?这将支持关于“货物狂欢节编程”的评论。
关于下面的评论,我做了一个测试,果然是typeid(array) == typeid(1 ? array : array),所以在某种意义上我是错的,但我的误解仍然可能与导致原始代码的误解相匹配!
发布于 2015-01-24 08:04:54
expr.typeid/2 (N3936)包含了这种行为:
当
typeid应用于类型为多态类类型的glvalue表达式时,结果将引用一个std::type_info对象,该对象表示glvalue引用的派生最多的对象(即动态类型)的类型。如果glvalue表达式是通过对指针应用一元*运算符获得的,并且该指针是空指针值,则typeid表达式将抛出与std::bad_typeidexception类型的处理程序匹配的类型的异常。
表达式1 ? *p : *p始终是左值。这是因为*p是一个左值,而expr.cond/4表示,如果三元运算符的第二个和第三个操作数具有相同的类型和值类别,则运算符的结果也具有该类型和值类别。
因此,1 ? *m_basePtr : *m_basePtr是一个类型为Base的左值。因为Base有一个虚拟析构函数,所以它是一个多态类类型。
因此,这段代码确实是一个“当typeid应用于其类型是多态类类型的glvalue表达式时”的示例。
现在我们可以阅读上面引用的其余部分。GL值表达式是“通过将一元*运算符应用于指针而获得的”-它是通过三元运算符获得的。因此,该标准不要求在m_basePtr为null时抛出异常。
在m_basePtr为null的情况下的行为将被更通用的关于取消引用null指针的规则所涵盖(这在C++中实际上是有点模糊的,但为了实际目的,我们假设它会导致未定义的行为)。
最后:为什么有人要写这篇文章?我认为好奇心的答案是到目前为止最合理的建议:使用这种构造,编译器不必插入空指针测试和代码来生成异常,因此它是一个微优化。
想必程序员要么很高兴,因为它永远不会被空指针调用,要么很高兴依赖于特定实现对空指针取消引用的处理。
发布于 2011-08-06 15:46:09
typeid(*m_basePtr)无论运行时类型如何,始终返回typeid(Base)。但将其转换为表达式/临时/rvalue会使编译器给出RTTI。
问题是哪个编译器,什么时候,等等。我想GCC在早期的typeid方面有问题,但这是一个模糊的记忆。
https://stackoverflow.com/questions/6795890
复制相似问题