4

我有一棵树,其中每个节点基本上如下所示:

struct node
{
    std::unordered_set<object*> objects;
    std::map<std::type_index,node> children;
};

当我遍历树以添加新类型时,我想做一个检查:

std::is_base_of<base,derived>

但是,我拥有的派生类型的唯一信息是type_index/type_info*.

无论如何我可以将其转换type_info*template参数吗?

如果没有,我的其他选择是什么?我想可以调用decltype(*objects.begin()),但这将要求每个节点中的每个集合都不能为空。

4

3 回答 3

7

无论如何我可以将其转换type_info*为模板参数吗?

不,没有办法。模板是编译时的东西,RTTI 是运行时的。两者之间没有任何联系。

我想可以调用decltype(*objects.begin()),但这将要求每个节点中的每个集合都不能为空。

它不需要那样。decltype不评估它的论点——它不需要。它只需要检查类型。你可以decltype(*a_null_pointer)不用调用 UB 就很高兴,因为表达式永远不会被计算——这就是所谓的未计算上下文sizeof属于同一类别。

请注意,这不会给您带来太多收益 - 您只会object*&回来。如果不首先准备映射,您通常无法从运行时信息中获取类型。

于 2013-04-05T11:44:56.630 回答
4

is_base_of并且decltype是纯粹的编译时构造;它们不会反映对象的动态类型。

type_info不提供检查子类关系的工具;在运行时执行该检查的唯一方法是使用dynamic_cast. 您需要存储 aunique_ptr<base>并查看它是否可以dynamic_cast用于派生类型。

于 2013-04-05T11:51:57.810 回答
4

如果我对您的理解正确,您需要一种类型inheritance_checker,使得它的每个实例都与一个类型相关联,但inheritance_checker它本身不是。类似于type_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

如果是这种情况,我可以建议你一些,不幸的是,可能会很慢!这取决于例外情况。

基本思想是,如果你抛出 aB*那么 acatch (A*)是匹配的。因此,我们赋予了inheritance_checker在构造时抛出和捕获指向给定类型的指针的能力。Butinheritance_checker不是模板,因此必须以类型擦除的方式提供此容量。这可以通过存储指向具有固定签名的函数的指针来完成,该签名不依赖于构造时传递的类型,但能够抛出/捕获指向给定类型的指针。inheritance_checker下面给出了一个可能的实现。

#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));
}

如果您愿意,您可以添加一个type_info*成员来inheritance_checker获得提供的额外功能type_info

is_base_of注意和之间的对称性derives_from。实际上,您可以删除其中之一。

我建议你阅读这篇文章。

于 2013-04-05T14:13:46.747 回答