奇怪的static_cast技巧?

Rob*_*Rob 10 c++ qt

在仔细阅读Qt源代码时,我遇到了这个gem:

template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item)
{
    return int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type)
        || (item && int(static_cast<T>(0)->Type) == item->type()) ? static_cast<T>(item) : 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意static_cast<T>(0)->Type?我已经使用C++很多年了,但之前从未见过0在static_cast中使用过.这段代码在做什么,是否安全?

背景:如果你从中派生出来QGraphicsItem的意思是声明一个名为的唯一枚举值Type,并实现一个名为return 的虚函数type,例如:

class Item : public QGraphicsItem
{
public:
  enum { Type = MAGIC_NUMBER };
  int type() const { return Type; }
  ...
};
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

QGraphicsItem* item = new Item;
...
Item* derivedItem = qgraphicsitem_cast<Item*>(item);
Run Code Online (Sandbox Code Playgroud)

这可能有助于解释static_cast正在尝试做什么.

Ash*_*ain 8

这看起来像一个非常可疑的方式来静态断言模板参数T有一个Type成员,然后验证它的值是预期的幻数,就像你说你应该做的那样.

由于Type是枚举值,因此this不需要指针来访问它,因此static_cast<Item>(0)->Type在Item::Type不实际使用指针值的情况下检索值.所以这可行,但可能是未定义的行为(取决于您对标准的看法,但IMO无论如何都是一个坏主意),因为代码使用指针取消引用operator(->)取消引用NULL指针.但是我无法想象为什么这比仅仅Item::Type模板或模板更好T::Type- 也许它的遗留代码设计用于具有较差模板支持的旧编译器,这些编译器T::Type无法解决所谓的意思.

尽管如此,最终的结果是代码qgraphicsitem_cast<bool>(ptr)会在编译时失败,因为bool没有Type成员枚举.这比运行时检查更可靠,更便宜,即使代码看起来像黑客.

  • 最后我读到有一些细微之处并且争论指针是否被解除引用(例如,如果`&*((int*)0)`由于明显的取消引用而未定义,即使它可以被跳过 - 或者调用静态成员函数通过一个空实例指针,这更像是在问题中发生的事情).IMO语言律师可以解决这个问题,我们凡人可以编写看起来不像是引用空指针的代码:) (2认同)

Did*_*set 5

这有点奇怪,是的,并且是官方未定义的行为.

也许他们可以按如下方式编写它(请注意,这里的T不再是指针,它是否是原始代码中的指针):

template <class T> inline T * qgraphicsitem_cast(const QGraphicsItem *item)
{
    return int(T::Type) == int(QGraphicsItem::Type)
        || (item && int(T::Type) == item->type()) ? static_cast<T *>(item) : 0;
}
Run Code Online (Sandbox Code Playgroud)

但是他们可能被constness咬了,并且被迫写了两个版本的同一个函数.也许是他们做出选择的理由.

  • @konrad:如果没有正确阅读标准,请不要那么自信.有关C,请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 (2认同)