C++ 如何从模板参数的类型信息中获取类型
我有一棵树,其中每个节点基本上如下所示:C++ 如何从模板参数的类型信息中获取类型,c++,templates,c++11,rtti,C++,Templates,C++11,Rtti,我有一棵树,其中每个节点基本上如下所示: struct node { std::unordered_set<object*> objects; std::map<std::type_index,node> children; }; struct节点 { std::无序的集合对象; 地图儿童; }; 当我在树上迭代以添加新类型时,我想做一个检查: std::is_base_of<base,derived> std::是 但是,对于派生类型
struct node
{
std::unordered_set<object*> objects;
std::map<std::type_index,node> children;
};
struct节点
{
std::无序的集合对象;
地图儿童;
};
当我在树上迭代以添加新类型时,我想做一个检查:
std::is_base_of<base,derived>
std::是
但是,对于派生类型,我仅有的信息是type\u索引/type\u信息*
我是否可以将type_info*
转换为模板
参数
如果没有,我的其他选择是什么?我想可以调用decltype(*objects.begin())
,但这将要求每个节点中的每个集合永远不为空
我是否可以将type\u info*
转换为模板参数
不,不可能。模板是编译时的,RTTI是运行时的。两者之间没有联系
我想可以调用decltype(*objects.begin())
,但这将要求每个节点中的每个集合永远不为空
它不需要这样做decltype
不计算其参数-不需要计算。它只需要检查类型。您可以在不调用UB的情况下愉快地执行decltype(*a_null_指针)
,因为表达式从未计算过-这就是所谓的未计算上下文sizeof
属于同一类别
不过,请注意,这并不能给您带来太多好处-您只需返回
object*&
。通常,如果不先准备映射,就无法从运行时信息中获取类型。是的基础,而decltype
纯粹是编译时构造;它们不会反映对象的动态类型
type_info
不提供检查子类关系的工具;在运行时执行该检查的唯一方法是使用dynamic\u cast
。您需要存储一个唯一的\u ptr
,并查看它是否可以动态\u cast
到派生类型。如果我理解正确,您需要一个类型继承检查器
,这样它的每个安装都与一个类型关联,但继承检查器
本身不关联。类似于类型\u ifo
的东西,但可以在运行时检查继承关系。例如,您希望以下各项正常工作:
class A {};
class B : public A {};
// Note that a and b have the same type but they are "related" to distinct types.
inheritance_checker a = inheritance_checker::create<A>();
inheritance_checker b = inheritance_checker::create<B>();
assert( a.is_base_of (b) );
assert( a.derives_from(a) ); // derives from or is equal to
assert( ! b.is_base_of (a) );
assert( b.derives_from(b) ); // derives from or is equal to
如果愿意,可以将type\u info*
成员添加到heritation\u checker
以获得type\u info
提供的额外功能
请注意,是
的基础,而派生自
。实际上,您可以删除其中一个
我建议你们读一读这篇文章。decltype(base*)给了我“真实”的驱动类型吗?因为我的object*集合包含的定义类型比object*多@David:哦,不,显然不是,因为它也只是编译时的东西。:)如果不事先准备映射,就无法从运行时信息中获取类型。您可以在第二段中明确添加以下内容:decltype(*objects.begin())
根本买不到任何东西,只返回object*
,即使你的第一段已经概括地说明了这一点。正如埃卡特穆尔所说,我显然需要做检查。但dynamic cast仍然采用类型而不是类型信息。所以我又回到了原点。@DavidJensen它不仅接受一个类型,还接受一个实际对象(或者更确切地说是一个指向一个对象的指针/引用)。但是你说你甚至没有一个对象,只有它的type\u info
?InterTesting,但是如果您仍然可以访问它,您将无法使用生成type_info
的对象。最后,现在可能是一个很好的时机来解释您试图在问题中更清楚地解决的实际问题。模板是在编译时计算的,您有一个type\u info
表示对象的运行时类型。这怎么可能呢。您已经知道它们的静态类型,它是object*
(这也是decltype(*objects.begin())
将返回的内容),但这对您没有任何帮助。所以模板是完全不可能的,因为它解决了一个完全不同的问题,不能用于RTTI。该死的,这会使我的树结构变慢。但是,dynamic_cast仍然需要一个真正的类型,而不是类型_info*。我又回到原点了。@David我们的想法是彻底摆脱type\u info
。这真是太棒了!我并没有完全遵循这一点,但它确实给了我一些想法!这里真正重要的是函数指针。我通过在创建节点时给节点一个lambda(比如您的继承检查器::create)实现了所需的功能。lambda是通过模板创建的,并调用dynamic_cast。然后我可以调用lambda而不需要模板。非常感谢。我知道可以混合使用静态和动态输入@David Jensen:事实上,如果您考虑的所有类型都来自同一个多态基类,那么使用dynamic\u cast
比像我这样使用throw
/catch
更有效。投掷
/捕获
技巧的优点是更通用,但代价是速度较慢。
#include <cassert>
class inheritance_checker {
typedef void (*thrower_t)();
typedef bool (*catcher_t)(thrower_t);
public:
template <typename T>
static inheritance_checker create() {
return inheritance_checker(concrete_thrower<T>, concrete_catcher<T>);
}
bool is_derived_from(const inheritance_checker& other) const {
return other.catcher_(thrower_);
}
bool is_base_of(const inheritance_checker& other) const {
return catcher_(other.thrower_);
}
private:
template <typename T>
static void concrete_thrower() {
throw static_cast<T*>(nullptr);
}
template <typename T>
static bool concrete_catcher(thrower_t thrower) {
try { thrower(); }
catch (T*) { return true; }
catch (...) { }
return false;
}
inheritance_checker(thrower_t thrower, catcher_t catcher) :
thrower_(thrower), catcher_(catcher) {
}
thrower_t thrower_;
catcher_t catcher_;
};
class A {};
class B : public A {};
class C : public B {};
class D {};
int main() {
auto a = inheritance_checker::create<A>();
auto b = inheritance_checker::create<B>();
auto c = inheritance_checker::create<C>();
auto d = inheritance_checker::create<D>();
assert( a.is_base_of(a));
assert( a.is_base_of(b));
assert( a.is_base_of(c));
assert(!a.is_base_of(d));
assert( a.is_derived_from(a));
assert(!a.is_derived_from(b));
assert(!a.is_derived_from(c));
assert(!a.is_derived_from(d));
assert(!b.is_base_of(a));
assert( b.is_base_of(b));
assert( b.is_base_of(c));
assert(!b.is_base_of(d));
assert( b.is_derived_from(a));
assert( b.is_derived_from(b));
assert(!b.is_derived_from(c));
assert(!b.is_derived_from(d));
assert(!c.is_base_of(a));
assert(!c.is_base_of(b));
assert( c.is_base_of(c));
assert(!c.is_base_of(d));
assert( c.is_derived_from(a));
assert( c.is_derived_from(b));
assert( c.is_derived_from(c));
assert(!c.is_derived_from(d));
assert(!d.is_base_of(a));
assert(!d.is_base_of(b));
assert(!d.is_base_of(c));
assert( d.is_base_of(d));
assert(!d.is_derived_from(a));
assert(!d.is_derived_from(b));
assert(!d.is_derived_from(c));
assert( d.is_derived_from(d));
}