如何使用整数id自动识别类层次结构中的类?

时间:2013-09-16 01:30:49

标签: c++ templates

例如,我有一个基类A及其子类BC等等。 BC也可以拥有其子类。该结构是一个具有根A的树。树中的每个类都分配了一个不同的整数来标识自己。整数id的值和顺序没有限制。确保不同类别的不同。

我的问题是如何通过使用类似模板技术巧妙地(或自动地)执行此操作,因为手动分配容易出错。任何获得id的方法都很好,比如

class A
{
public:
    static const id = ...;
};

template<class A>
struct Id
{
    enum { value = ... };
};

2 个答案:

答案 0 :(得分:1)

最简单的方法只是一个功能

int nextId() {
    static int rval = 1;
    return rval++;
}

class A { public: static const id = nextId();  };
class B { public: static const id = nextId();  };
class C { public: static const id = nextId();  };

只要您不需要在程序开始时使用动态初始化中的ID,这将有效。

编辑:如果这还不够,下一步就是对模板中的静态变量做同样的事情。这适用于编译单元,但仍然是动态初始化时间。

template <typename DummyT = void>
struct CommonCounter
{
    public:
        static int nextId() {
            static int rval = 1;
            return rval ++;
        }
};

template <typename T>
struct IdFor
{
    static int value()
    {
        static int rval = CommonCounter<>::nextId();
        return rval;
    }
};

class A { public: static const id = IdFor<A>::get(); };

答案 1 :(得分:1)

你可以这样做。这应该在同一个编译器上给出相同的顺序。您还可以修改关键字以获取已知订单并在初始化时检测问题。简单的实现,未经过测试。

#include <typeinfo>

class A {
public:
    virtual ~A();
    static void register_type(std::type_info const& t);
    int id() const;
};

template<class T>
struct DoInitA
{
    DoInitA() { A::register_type(typeid(T)); }
};

class B : public A
{
    static DoInitA<B> s_a_init;
public:
    ~B() { }
};

//
// Implementation file.
//

#include <vector>
#include <functional>

namespace {
    struct TypeinfoLess {
        typedef std::reference_wrapper<const std::type_info> value_type;

        bool operator()(value_type const& lhs, value_type const& rhs) const {
            return lhs.get().before(rhs.get());
        }
    };
}

typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;

static TypeVector s_types;
static bool s_init_complete = false;

A::~A() { }

void A::register_type(std::type_info const& t)
{
    static int s_counter = 0;
    if (s_init_complete)
        throw std::runtime_error("Late initialisation");

    s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}

int A::id() const
{
    if (!s_init_complete) {
        sort(s_types.begin(), s_types.end(), TypeinfoLess());
        s_init_complete = true;
    }

    for (size_t i = 0; i < s_types.size(); ++i)
        if (s_types[i].get() == typeid(*this)) return i;

    throw std::runtime_error("Uninitialised type");
}