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

How to use an integer id to identify a class in a class hierarchy automatically?

本文关键字:层次结构 标识 何使用 整数 id      更新时间:2023-10-16

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

我的问题是如何通过使用类似的模板技术来巧妙地(或自动)做到这一点,因为手动分配很容易出错。任何获取 id 的方法都可以,例如

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

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

最简单的方法只是一个函数

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

你可以做这样的事情。这应该在同一编译器上给出相同的顺序。您还可以修改键入内容的方式,以获取已知订单并在初始化时检测问题。简单的实施,未经测试。

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