在仔细阅读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正在尝试做什么.
这看起来像一个非常可疑的方式来静态断言模板参数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成员枚举.这比运行时检查更可靠,更便宜,即使代码看起来像黑客.
这有点奇怪,是的,并且是官方未定义的行为.
也许他们可以按如下方式编写它(请注意,这里的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咬了,并且被迫写了两个版本的同一个函数.也许是他们做出选择的理由.
| 归档时间: |
|
| 查看次数: |
2472 次 |
| 最近记录: |