类类型信息MACRO可以用模板替换吗



我有一个传统的大型类继承树(域类(,它实现了自己的类类型信息和注册表。它的实现方式是每个类"调用"像这样的宏

class MyClass : public MyParent {
MY_DECLARE_DYNAMIC(MyClass)
...
};
//in .c file:
MY_IMPLEMENT_DYNAMIC(MyClass, MyParent)

基本上,这些宏插入一个静态函数,该函数是meyer的单例,返回一个指向MyClassInfo的指针,如下所示:

class MyClass : public MyParent {
MyClassInfo* GetClassInfo_() {
static MyClassInfo instance=...;
return &instance;
}
virtual MyClassInfo* GetClassInfo() const;
};

宏插入的另一个东西是一个虚拟函数,用于检索类信息以供运行时使用(即从某个基类型指针(。

MyClassInfo*保存类的字符串名称以及获取父类信息的某种方式(实现目前使用函数指针(。

此信息现在可以直接写入使用:MyClass::GetClassInfo_()myClass.GetClassInfo()

在实际情况下,有(正如你可能已经猜到的(更多的细节,但我认为这足以说明这个概念,只是说每个类都可以有更多的特征,比如数据(例如,一个枚举值,指示这个特定类是否被弃用(

这种模式在WxWidgets和MFC中也是众所周知的https://learn.microsoft.com/en-us/previous-versions/ywz9k63y(v=vs.140(

有人有办法摆脱这些MACRO吗?除了手工编写所有内容之外,例如使用模板或虚拟继承等。最好是一个不增加每个对象大小的对象(不止一个虚拟函数(。

让代码变得更好的一个合理而简单的方法就是将MyClassInfo的静态实例完全移出类,并使其成为模板化函数:

这里有一个完整的例子:

#include <type_traits>
class MyClassInfo {
public:
virtual ~MyClassInfo() {}
virtual MyClassInfo* get_parent() const = 0; 
};
template<typename T>
MyClassInfo* get_class_info();
template<typename T>
class MyClassInfo_impl : public MyClassInfo {
public:
using parent_t = typename T::parent_t;
MyClassInfo* get_parent() const override {
if constexpr(std::is_same_v<parent_t, void>) {
return nullptr;
}
else {
return get_class_info<parent_t>();
}
}
};
template<typename T>
MyClassInfo* get_class_info() {
static MyClassInfo_impl<T> impl;
return &impl;
}
class Parent {
public:
// Could probably be inferred through SFINAE instead.
using parent_t = void;
};
class MyClass : public Parent {
public:
using parent_t = Parent;
virtual MyClassInfo* GetClassInfo() { 
return get_class_info<MyClass>();
} 
};
int main() {
auto class_info = get_class_info<MyClass>();
}

这样,您只剩下虚拟函数,正如您在评论中提到的,它在处理任何基于继承的解决方案时都会变得非常混乱。

还有一个实现,在模板包装器上具有层次结构。我使用RTTI来获取类名,这可以通过将名称传递到构造函数来避免。

#include <iostream>
#include <memory>
#include <type_traits>
struct class_info {
const char* name;
const class_info* parent;
};
template<class C>
constexpr const char* class_name() noexcept
{
return typeid(C).name();
}
class object
{
protected:
constexpr object() noexcept
{}
public:
virtual class_info* get_class_info() {
static class_info _instance = {"object",nullptr};
return &_instance;
}
};
template<class Base,class Derived>
class reflective:public Base {
reflective(const reflective&) = delete;
reflective& operator=(const reflective&) = delete;
protected:
constexpr reflective() noexcept:
Base()
{
static_assert( std::is_base_of<object,Base>::value && std::is_base_of<Base,Derived>::value , "Base must inherit object, and Derived must inherit base" );
}
public:
virtual class_info* get_class_info() override {
static class_info _instance = {::class_name<Derived>(), Base::get_class_info() };
return &_instance;
}
};
class offspring_0 :public reflective<object,offspring_0> {
public:
constexpr offspring_0() noexcept:
reflective<object,offspring_0>()
{}
};
class offspring_1 : public reflective<offspring_0,offspring_1> {
public:
constexpr offspring_1() noexcept:
reflective<offspring_0,offspring_1>()
{}
};
int main(int argc, const char** argv) {
std::shared_ptr<object> offspring = std::make_shared<offspring_1>();
const class_info *ci = offspring->get_class_info();
std::cout << "Self name: " << ci->name << std::endl;
unsigned i = 1;
for(ci = ci->parent; ci != nullptr; ci = ci->parent) {
for(unsigned j=0; j < i; j++)
std::cout << 't';
std::cout<< "parent " << i << " name: " << ci->name << std::endl;
++i;
}
return 0;
}

输出:

Self name: 11offspring_1
parent 1 name: 11offspring_0
parent 2 name: object
Process returned 0 (0x0)   execution time : 0.084 s
Press any key to continue.
template<typename base_class, type_name crtp_class>
class h_traits{
public:
using this_type=crtp_class;
using base_type=base_class;
using traits_class=h_traits;
static_assert(std::is_same_v<base_class, typename base_class::this_type>, "invalid hierarchy");
//Rest of definitions follows
//...
};
class object_base//grand common base
{
public:
using this_type=object_base;
//... 
};
//...
class my_new_class: 
public h_traits<my_old_class, my_new_class>
{
//...
};

最新更新