来自http://llvm.org/docs/CodingStandards.html#ci_rtti_exceptions
LLVM确实广泛使用了 使用的RTTI手卷形式 模板,如isa<>,cast<>和 dyn_cast<取代。这种形式的RTTI是 选择加入并可以添加到任何类。 它也是更多 效率高于dynamic_cast<>。
isa和其他人是如何实施的?
答案 0 :(得分:31)
首先,LLVM系统非常具体,并不是RTTI系统的直接替代品。
<强>处所强>
识别对象类
采用简单的层次结构,例如:
struct Base {}; /* abstract */
struct DerivedLeft: Base {}; /* abstract */
struct DerivedRight:Base {};
struct MostDerivedL1: DerivedLeft {};
struct MostDerivedL2: DerivedLeft {};
struct MostDerivedR: DerivedRight {};
我们将创建一个特定于此层次结构的枚举,其中每个层次结构成员的枚举成员都可以实例化(其他成员将无用)。
enum BaseId {
DerivedRightId,
MostDerivedL1Id,
MostDerivedL2Id,
MostDerivedRId
};
然后,Base
类将使用一个返回此枚举的方法进行扩充。
struct Base {
static inline bool classof(Base const*) { return true; }
Base(BaseId id): Id(id) {}
BaseId getValueID() const { return Id; }
BaseId Id;
};
每个具体的课程也以这种方式得到增强:
struct DerivedRight: Base {
static inline bool classof(DerivedRight const*) { return true; }
static inline bool classof(Base const* B) {
switch(B->getValueID()) {
case DerivedRightId: case MostDerivedRId: return true;
default: return false;
}
}
DerivedRight(BaseId id = DerivedRightId): Base(id) {}
};
现在,简单地说,可以查询确切的类型,以便进行投射。
隐藏实施细节
让用户使用getValueID
进行操作会很麻烦,因此在LLVM中使用classof
方法隐藏了这些内容。
给定的类应该实现两个classof
方法:一个用于其最深的基础(测试BaseId
的合适值)和一个用于自身(纯优化)。例如:
struct MostDerivedL1: DerivedLeft {
static inline bool classof(MostDerivedL1 const*) { return true; }
static inline bool classof(Base const* B) {
return B->getValueID() == MostDerivedL1Id;
}
MostDerivedL1(): DerivedLeft(MostDerivedL1Id) {}
};
这样,我们可以通过模板检查是否可以进行强制转换:
template <typename To, typename From>
bool isa(From const& f) {
return To::classof(&f);
}
想象一下,To
是MostDerivedL1
:
From
是MostDerivedL1
,那么我们会调用classof
的第一个重载,并且它可以正常工作From
是其他任何东西,那么我们调用classof
的第二个重载,并且检查使用枚举来确定具体类型是否匹配。希望它更清楚。
答案 1 :(得分:6)
只需在osgx的答案中添加内容:基本上每个类都应该实现classof()方法,该方法可以完成所有必要的操作。例如,Value的classof()例程如下所示:
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Value *) {
return true; // Values are always values.
}
要检查我们是否有适当类型的类,每个类都有唯一的ValueID。您可以在include / llvm / Value.h文件中查看ValueID的完整列表。此ValueID的用法如下(摘自Function.h):
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Function *) { return true; }
static inline bool classof(const Value *V) {
return V->getValueID() == Value::FunctionVal;
}
因此,简而言之:每个类都应该实现执行必要决策的classof()方法。有问题的实现包含一组唯一的ValueID。因此,为了实现classof(),只需将参数的ValueID与自己的ValueID进行比较。
如果我没记错的话,isa&lt;&gt;的第一个实现大约10年前,朋友们被提升了。现在,实现有很大分歧:)
答案 2 :(得分:5)
我应该提到http://llvm.org/docs/ProgrammersManual.html#isa - 本文档有一些额外的描述。
isa,cast和dyn_cast的源代码位于单个文件中,并且评论很多。
http://llvm.org/doxygen/Casting_8h_source.html
00047 // isa<X> - Return true if the parameter to the template is an instance of the
00048 // template type argument. Used like this:
00049 //
00050 // if (isa<Type*>(myVal)) { ... }
00051 //
00052 template <typename To, typename From>
00053 struct isa_impl {
00054 static inline bool doit(const From &Val) {
00055 return To::classof(&Val);
00056 }
00057 };
00193 // cast<X> - Return the argument parameter cast to the specified type. This
00194 // casting operator asserts that the type is correct, so it does not return null
00195 // on failure. It does not allow a null argument (use cast_or_null for that).
00196 // It is typically used like this:
00197 //
00198 // cast<Instruction>(myVal)->getParent()
00199 //
00200 template <class X, class Y>
00201 inline typename cast_retty<X, Y>::ret_type cast(const Y &Val) {
00202 assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
00203 return cast_convert_val<X, Y,
00204 typename simplify_type<Y>::SimpleType>::doit(Val);
00205 }
00218 // dyn_cast<X> - Return the argument parameter cast to the specified type. This
00219 // casting operator returns null if the argument is of the wrong type, so it can
00220 // be used to test for a type as well as cast if successful. This should be
00221 // used in the context of an if statement like this:
00222 //
00223 // if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
00224 //
00225
00226 template <class X, class Y>
00227 inline typename cast_retty<X, Y>::ret_type dyn_cast(const Y &Val) {
00228 return isa<X>(Val) ? cast<X, Y>(Val) : 0;
00229 }