关于自省:定义自省C类层次描述的有效方法?

 2021-04-09 

Efficient way to define an introspective C++ class hierararchy description ?

我有一个通过继承定义的C类层次结构,并将此层次结构的描述存储在其中,以后可用于自省。我想知道是否有比我目前更有效或更干净的方法来定义此方法。
这是我的代码的精简版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// in header file (hpp)
struct Type
{
    Type( const string& n, const Type* p = nullptr ) : name(n), parent(p) {}
    const string name;
    const Type* parent;
};

class Base
{
public:
    static const Type m_type;
    virtual const Type& type() const { return m_type; }
};

class Derived : public Base
{
public:
    static const Type m_type;
    const Type& type() const { return m_type; }
};

// in implementation file (cpp)
const Type Base::m_type("Base" );
const Type Derived::m_type("Derived", &Base::m_type );


不一定高效,但是请考虑您是否真的需要一个通用的基类。一种替代方法是使用全局类型信息注册表。然后通过TypeInfo::get(my_variable)TypeInfo::get(typeid(my_type))查询类型的类型信息。

其优点是它也可以与现有类型一起使用,只需将其添加到此类型信息注册表中即可。

在内部,注册表将使用从std::type_infoType或类似的映射。以下是概念证明。不幸的是,该代码无法在clang或GCC上编译。根据错误消息,我怀疑是错误,但我也可能是错误的||

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct Type {
    std::string name;
    std::vector<Type*> parents;
    // TODO Extend by fully-qualified name (namespace) etc.

    template <typename... T>
    Type(std::string&& name, T*... parents)
        : name(name), parents{parents...} { }
};

struct TypeInfo {
    template <typename T>
    static Type const& get(T const&) { return get(typeid(T)); }

    template <typename T>
    static Type const& get() { return get(typeid(T)); }

    static Type const& get(std::type_info const& info) {
        auto i = types.find(info);
        if (i == types.end())
            throw unknown_type_error(info.name());

        return i->second;
    }

    template <typename T>
    static void register_type(Type&& type) {
        types.insert(std::make_pair(typeid(T), type));
    }

    typedef std::unordered_map<std::type_info, Type> type_dir_t;
    static type_dir_t types;
};

完整的代码可以在github上找到。

在C中通常不赞成在逻辑上不相关的类使用公共基类,尽管可以认为这类似于CRTP / mixin,在这种情况下,鼓励使用公共基类。因此,我想说,如果您不关心现有类型,则该方法不一定有任何错误。