类的注册,通过调用 registraton::class_<T>(“name”),尖括号内是要注册的类型,小括号内是自定义名称。 注册过程首先会调用 type::get<T>(),拿到属于这个类的type实例,然后调用detail::type_register::custom_name(t, name),将类与自定义的名称进行绑定,绑定完以后在后面的代码里面就可以通过 type::get_by_name(“class name”) 来获取该类的type实例,而无需通过类本体来获取。
custom_name 实际是调用 type_register_private 的register_custom_name 来实现的,register_custom_name首先调用update_custom_name,它的功能就是修改m_type_data上的name,但是不修改m_type_data的type_name。然后以name为key放入map,这样就可以通过自定义的名称来寻找type了,也就是通过字符串反射类型。
void type_register_private::update_custom_name(std::string new_name, const type& t)
{
std::lock_guard<std::mutex> lock(m_mutex);
auto& type_name = t.m_type_data->name;
if (new_name != type_name)
{
m_custom_name_to_id.erase(type_name);
type_name = std::move(new_name);
m_custom_name_to_id.insert(std::make_pair(type_name, t));
}
}
void type_register_private::register_custom_name(type& t, string_view custom_name)
{
if (!t.is_valid())
return;
update_custom_name(custom_name.to_string(), t);
...
}
修改配对name后,需要对该类相关的type命名进行修改。接着代码有两个循环(见下方代码),第一个循环,因为 t 的名字被自定义过了,那么 t* 或者 t[] 这样的类型名字也需要修改,比如 t 修改为 “cc ” ,那么 t* 的自定义名也需要同步修改为 “cc*”。第一个循环会遍历所有已有的类型,对所有的type,除了刚刚注册的t类型以外(tt == t || tt.get_raw_type() == tt),遍历到的type会通过derive_name函数去获取正确的类型名。比如我们前面注册了一个 std::string 的类型,那这里正好遍历到了 std::string* 的类型,这时 std::string* 的名字会是 classstd::basic_string,classstd::allocator >* ,derive_name 会通过 raw_type 的名字获取类型名为 std::string* ,然后在通过 update_custom_name 更新到 map 中去。具体 derive_name 的算法就是字符串操作,比较简单,大家可以自行阅读代码。
void type_register_private::register_custom_name(type& t, string_view custom_name)
{
...
auto tmp_type_list = m_custom_name_to_id.value_data();
for (auto& tt : tmp_type_list)
{
if (tt == t || tt.get_raw_type() == tt)
continue;
auto new_name = derive_name(tt);
update_custom_name(new_name, tt);
}
...
}
第二个循环的功能和第一个类似,代码如下,功能是如果刚刚注册的类型的衍生类型是模板类型的话,那么所有的衍生类型也要带上相同的模板。比如 A<T> 类型注册为 “A<T>”,那么如果map列表里面有 A<T>* 类型会改名为 “A<T>*”,derive_template_instance_name 就是处理字符串功能的函数。
void type_register_private::register_custom_name(type& t, string_view custom_name)
{
...
for (auto& tt : tmp_type_list)
{
if (tt == t || !tt.is_template_instantiation())
continue;
update_custom_name(derive_template_instance_name(tt.m_type_data), tt);
}
...
}
以上部分就是类型的注册,主要是把类型和自定义名称进行绑定,有了自定义名称就可以通过自定义名称找到对应的type,有了对应的type就可以构造对应类型的对象,不过在构造对象之前需要为type注册相应的构造函数,没有构造函数,type是不能创建实例的,下一节将介绍构造函数的注册。