C++

1 模板参数表指定类型判断

  • rttr/detail/misc/misc_type_traits.h

判断一个类型是不是在类型列表中

比如有这样一个场景,有 as_raw_pointer, as_object, as_std_shared_ptr 三种类型,需要判断用户模板传入的一个类型是不是这三个其中的一个。

struct as_raw_pointer {};
struct as_object {};
struct as_std_shared_ptr {};

using constructor_policy_list = type_list<as_raw_pointer, as_object, as_std_shared_ptr>;

// 希望得到的方式
template <T>
struct Check {
    // 比如这里需要判断这个T是不是 as_raw_pointer, as_object, as_std_shared_ptr 其中的一种。
}
阅读更多 »1 模板参数表指定类型判断

8 type注册

  • rttr/detail/type/type_register.cpp

type data构造完了后会加入到registration_manager,通过调用registration_manager的单例的add_item函数。

type_data* add_item(std::unique_ptr<type_data> obj)
{
    auto reg_type = type_register::register_type(obj.get());
    const auto was_type_stored = (reg_type == obj.get());
    if (was_type_stored)
        m_type_data_list.push_back(std::move(obj)); // so we have to unregister it later
    return reg_type;
}
阅读更多 »8 type注册

9 class注册

类的注册,通过调用 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了,也就是通过字符串反射类型。

阅读更多 »9 class注册

7 type_data构造

  • rttr/type.h
  • rttr/wrapper_mapper.h
  • rttr/detail/type/type_impl.h
  • rttr/detail/type/type_data.h
  • rttr/detail/type/type_data.cpp
  • rttr/detail/impl/wrapper_mapper_impl.h

type实例的保存在第一章已经讲过,是通过模板类的单例来实现的,因此创建type实例的过程就是通过 type::get<T> 的方式去创建,既可以是主动的,也可以是被动的。

  • 被动就是在使用的时候去get一个type,如果从程序启动开始一直没有去get这个类型的type,那么rttr就会创建一个。
  • 主动就是在程序初始化的某一刻,将需要的type全部都get一遍,这样,在程序真正运行过程中就不需要去创建这些类型了。这种方式在后面注册class的时候会用到。
阅读更多 »7 type_data构造

5 variant policy代码解读1

  • rttr/detail/variant/variant_data_policy.h

1. variant_data_policy_empty

variant_data_policy_empty用作构造空的variant的时候,也就是variant构造时不传参数时m_policy使用的默认policy,因此这个policy也没有太多的可操作的部分,基本上取值就是返回nullptr,取类型拿到的就是invalid_type,也没有提供create的操作,因此这个policy不做详解。

2. variant_data_policy_void

variant_data_policy_void用于操控void类型的变量,对于void类型来说,大多数的操作都有没有意义的,比如create,clone,swap,接下来只解读有意义的操作,具体的源代码可以去查阅 variant_data_policy_void::invoke

阅读更多 »5 variant policy代码解读1

4 variant policy选择调用

  • rttr/detail/variant/variant_data_policy.h

variant_data_policy的选择

variant_policy的功能就是对包裹在variant里的数据本体进行操作,由于C++的数据类型过多,rttr将policy分成了以下9种。

  • variant_data_policy_empty //构造policy时的默认值
  • variant_data_policy_void // void类型policy
  • variant_data_policy_nullptr_t // nullptr类型的policy
  • variant_data_policy_string // std::string类型和一维char类型的policy
  • variant_data_policy_arithmetic // 算术类型的policy(int, short …)
  • variant_data_policy_small // 小容量类型的类, 容量小于variant_data
  • variant_data_policy_array_small // 小容量的数组,容量小于variant_data
  • variant_data_policy_big // 大容量的类,容量大于 variant_data
  • variant_data_policy_array_big // 大容量类型,超过variant_data容量的类型

对于给定的类型,首先要给定这个类型选用合适的policy,判定方法如下。下面的代码看似很吓人,其实用逻辑代码来表示的话无非就是套了好几层的 if-else,注释也都写在里面了,最终的目的就是从上述的9个policy里面找到一个合适 T类型 的policy。

阅读更多 »4 variant policy选择调用

3 variant构造

  • rttr/variant.h
  • rttr/variant.cpp
  • rttr/detail/variant/variant_impl.h

rttr的variant主要的功能将对象类型擦除后用于统一传递和保存,同时在variant构造的时候会同时保存传入对象的type信息,方便以后恢复。

variant的构造

先看variant一个最重要的构造函数。

template<typename T, typename Tp = detail::decay_variant_t<T>>
variant(T&& val) : m_policy(&detail::variant_policy<Tp>::invoke)
{
    detail::variant_policy<Tp>::create(std::forward(val), m_data);
} 
阅读更多 »3 variant构造

2 解读argument_wrapper

  • rttr/detail/misc/argument_wrapper.h

argument_wrapper是将变量右值地址保存成void* m_data中,用于函数参数的传递,所以argument_wrapper是不控制变量的生存期,生存期由外部调用者控制。

1. argument_wrapper的构造

argument_wrapper() : m_data(nullptr) {}

template<typename T, typename Tp = typename std::enable_if<
  !std::is_same<T, argument_wrapper>::value, T>::type>
argument_wrapper(T&& data) : m_data(const_cast<void*>(
  reinterpret_cast<const void*>(std::addressof(data)))) {}
  • argument_wrapper有2个构造函数,第一个构造函数用于传递空参数。
  • 第二个构造函数就是将右值的指针保存起来,待invoke的时候在取出使用。它的第一个模板参数就是传进来的值的类型,第二个模板参的功能是防止传入的参数也是一个argument_wrapper类型,这个是不允许的。
  • 给m_data的赋值的过程实际上就是把传入的变量的地址转成void*赋给m_data,因为传入的对象是一个右值,因此它可能是const的也可能不是const,而reinterpret_cast不能把const转成非const,但是非const是可以const,所以 reinterpret_cast 将指针统一转成 const void* 再通过const_cast 转成 void* 赋值给m_data。
阅读更多 »2 解读argument_wrapper

1 初识rttr


1. 介绍

rttr全称 Run Time Type Reflection ,是c++的一个运行时反射库。rttr的代码可以说是一场个人show,功能强大,代码花哨,作者将C++11/14的特性使用的淋漓尽致。如果你是一个C++新兵,我不建议你直接研究下面的代码,会搞得你晕头转向,而且大多数人写代码的时候也不会这样去写。

目前最新的master版本作者还在不断的更新修改,因此这次源码解读就选用了0.96的稳定版。

阅读更多 »1 初识rttr