02 静态反射

静态反射

更规范的基本萃取代码

  • 命名空间隔绝内部代码(details/internal)

  • basic_xxx_traits提供xxx的基本的信息

  • xxx_traits根据是否是class field提供模板特化

  • 宏定义便于快速完成

variable_traits.hpp

#pragma once
#include <type_traits>

namespace detail
{
template <typename T> struct variable_type {
using type = T;
};

template <typename Class, typename T> struct variable_type<T Class::*> {
using type = T;
};
} // namespace detail

template <typename T>
using variable_type_t = typename detail::variable_type<T>::type;

namespace internal
{
template <typename T> struct basic_variable_traits {
using type = variable_type_t<T>;
static constexpr bool is_member = std::is_member_pointer_v<T>;
};
} // namespace internal

template <typename T>
struct variable_traits;

template <typename T>
struct variable_traits<T*> : internal::basic_variable_traits<T> {
using pointer_type = T*;
};

template <typename Class, typename T>
struct variable_traits<T Class::*> : internal::basic_variable_traits<T Class::*> {
using pointer_type = T Class::*;
using class_type = Class;
};

function_traits.hpp

#pragma once
#include <type_traits>
#include <tuple>

namespace detail
{
template <typename Func>
struct basic_function_traits;

template <typename Ret, typename... Args>
struct basic_function_traits<Ret(Args...)> {
using args_type = std::tuple<Args...>;
using return_type = Ret;
};

template <typename Ret, typename Class, typename... Args>
struct basic_function_traits<Ret(Class::*)(Args...)> {
using args_type = std::tuple<Args...>;
using return_type = Ret;
};

} // namespace detail

template <typename Func>
struct function_traits;

template <typename Ret, typename... Args>
struct function_traits<Ret(Args...)> : detail::basic_function_traits<Ret(Args...)> {
using type = Ret(Args...);
using args_type = typename detail::basic_function_traits<Ret(Args...)>::args_type;
using function_pointer_type = Ret(*)(Args...);
static constexpr bool is_member = false;
static constexpr bool is_const = false;
};

template <typename Ret, typename Class, typename... Args>
struct function_traits<Ret(Class::*)(Args...)> : detail::basic_function_traits<Ret(Class::*)(Args...)> {
using type = Ret(Class::*)(Args...);
using args_type = typename detail::basic_function_traits<Ret(Class::*)(Args...)>::args_type;
using args_with_class_type = std::tuple<Class*, Args...>;
using function_pointer_type = Ret(Class::*)(Args...);
static constexpr bool is_member = true;
static constexpr bool is_const = false;
};

template <typename Ret, typename Class, typename... Args>
struct function_traits<Ret(Class::*)(Args...) const> : detail::basic_function_traits<Ret(Class::*)(Args...) const> {
using type = Ret(Class::*)(Args...) const;
using args_type = typename detail::basic_function_traits<Ret(Class::*)(Args...) const>::args_type;
using args_with_class_type = std::tuple<Class*, Args...>;
using function_pointer_type = Ret(Class::*)(Args...) const;
static constexpr bool is_member = true;
static constexpr bool is_const = true;
};


type_info.hpp

#pragma once
#include "function_traits.hpp"
#include "variable_traits.hpp"
#include <string_view>

template <typename T>
struct is_function
{
static constexpr bool value = std::is_function_v<std::remove_pointer_t<T>> ||
std::is_member_function_pointer_v<T>;
};

template <typename T>
using is_function_v = is_function<T>::value;

template <typename T>
struct field_traits;

template <typename T, typename Class>
struct field_traits<T Class::*> : variable_traits<T Class::*>{
constexpr field_traits(std::string_view name, T Class::* ptr) : name(name), ptr(ptr) {};
std::string_view name;
T Class::*ptr;
};

template <typename Ret, typename Class, typename... Args>
struct field_traits<Ret(Class::*)(Args...)> : function_traits<Ret(Class::*)(Args...)>{
using func_ptr_type = Ret(Class::*)(Args...);
constexpr field_traits(std::string_view name, func_ptr_type ptr) : name(name), ptr(ptr) {};
std::string_view name;
func_ptr_type ptr;
};

template <typename T>
struct TypeInfo;


#define BEGIN_CLASS(T) \
template <> \
struct TypeInfo<T> \
{

#define DECLARE_FUNCTIONS(...) \
static constexpr auto functions = std::make_tuple(__VA_ARGS__);

#define FUNCTION(F) function_traits<decltype(F)>{}
#define FUNCTION_FIELD(F) field_traits<decltype(F)>{#F, F}

#define DECLARE_VARIABLES(...) \
static constexpr auto variables = std::make_tuple(__VA_ARGS__);

#define VARIABLE(F) variable_traits<decltype(F)>{}
#define VARIABLE_FIELD(F) field_traits<decltype(F)>{#F, F}

#define END_CLASS() };


使用

#include "type_info.hpp"
#include <string>
#include <iostream>

class Person
{
public:
std::string familyName = "Hat";
std::string name = "John";
bool GetMerried(Person& p) { return true; }
std::string IntroduceMyself() { return name;}
};

BEGIN_CLASS(Person)
DECLARE_FUNCTIONS(FUNCTION_FIELD(&Person::GetMerried), FUNCTION_FIELD(&Person::IntroduceMyself))
DECLARE_VARIABLES(VARIABLE_FIELD(&Person::familyName), VARIABLE_FIELD(&Person::name))
END_CLASS()

template <typename Tuple, size_t ...Idx>
void print_tuple(const Tuple& t, std::index_sequence<Idx...>)
{
((std::cout << std::get<Idx>(t).name << '\n'), ...);
}

#define print_tuple_helper(tuple) print_tuple(tuple, std::make_index_sequence<std::tuple_size_v<decltype(tuple)>>())

template <size_t Idx, typename Class, typename Tuple>
void print_variables(Class& instance, Tuple& t)
{
if constexpr(Idx >= std::tuple_size_v<Tuple>)
{
return;
}
else
{
auto elem = instance.*(std::get<Idx>(t).ptr);
std::cout << elem << '\n';
print_variables<Idx + 1>(instance, t);
}
}

int main(int argc, char const *argv[])
{
TypeInfo<Person> info;
Person p;
print_tuple_helper(info.functions);
print_variables<0>(p, info.variables);
return 0;
}