0

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

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

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

或者

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

2 回答 2

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");
}
于 2013-09-16T02:33:33.100 回答
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(); };
于 2013-09-16T01:33:27.413 回答