-#define is_ex_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<GiNaC::basic *>((OBJ).bp))!=0)
-
-#define is_ex_exactly_of_type(OBJ,TYPE) \
- ((*(OBJ).bp).tinfo()==GiNaC::TINFO_##TYPE)
-
-#else // ndef NO_NAMESPACE_GINAC
-
-#define is_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<basic *>(&OBJ))!=0)
-
-#define is_exactly_of_type(OBJ,TYPE) \
- ((OBJ).tinfo()==TINFO_##TYPE)
-
-#define is_ex_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<basic *>((OBJ).bp))!=0)
-
-#define is_ex_exactly_of_type(OBJ,TYPE) \
- ((*(OBJ).bp).tinfo()==TINFO_##TYPE)
-
-#endif // ndef NO_NAMESPACE_GINAC
+/** Check if obj is a T, including base classes. */
+template <class T>
+inline bool is_a(const basic &obj)
+{
+ return dynamic_cast<const T *>(&obj) != 0;
+}
+
+/** Check if obj is a T, not including base classes. This one is just an
+ * inefficient default. It should in all time-critical cases be overridden
+ * by template specializations that use the TINFO_* constants directly. */
+template <class T>
+inline bool is_exactly_a(const basic &obj)
+{
+ return obj.tinfo() == T::get_class_info_static().options.get_id();
+}