c++结构体字段反射

c++的动态反射

#include <iostream>
#include <vector>
#include <string>
#include <functional>

template <typename FieldType>
using ValueConverter = std::function<void(FieldType* field, const std::string& name)>;


template <typename StructType>
class FieldConverterBase{
public:
    virtual ~FieldConverterBase() = default;
    virtual void operator()(StructType* obj) const = 0;
};

template <typename StructType, typename FieldType>
class FieldConverter : public FieldConverterBase<StructType> {
public:
    FieldConverter(const std::string& name,
                   FieldType StructType::*pointer,
                   ValueConverter<FieldType> converter)
            : field_name_(name),
              field_pointer_(pointer),
              value_converter_(converter) {}

    void operator()(StructType* obj) const override {
        return value_converter_(&(obj->*field_pointer_), field_name_);
    }

private:
    std::string field_name_;
    FieldType StructType::*field_pointer_;
    ValueConverter<FieldType> value_converter_;
};

template <class StructType>
class StructValueConverter {
public:
    template <typename FieldType>
    void RegisterField(FieldType StructType::*field_pointer,
                       const std::string& field_name,
                       ValueConverter<FieldType> value_converter) {
        fields_.push_back(std::make_unique<FieldConverter<StructType, FieldType>>(
                field_name, field_pointer, std::move(value_converter)));
    }

    void operator()(StructType* obj) const {
        for (const auto& field_converter : fields_) {
            (*field_converter)(obj);
        }
    }

private:
    std::vector<std::unique_ptr<FieldConverterBase<StructType>>> fields_;
};

struct  SimpleStruct{
    double double_;
    std::string string_;
};

int main()
{

    auto int_converter = [](double * field, const std::string& name) {
        std::cout << name << ": " << *field << std::endl;
    };
    auto string_converter = [](std::string* field, const std::string& name) {
        std::cout << name << ": " << *field << std::endl;
    };


    StructValueConverter<SimpleStruct> converter;
    converter.RegisterField(&SimpleStruct::double_, "double",
                            ValueConverter<double>(int_converter));
    converter.RegisterField(&SimpleStruct::string_, "string",
                            ValueConverter<std::string>(string_converter));

    SimpleStruct simple{10.22, "动态反射!"};
    converter(&simple);

    return 1;
}

c++的静态反射

#include <tuple>
#include <type_traits>

namespace detail {

    template <typename Fn, typename Tuple, std::size_t... I>
    inline constexpr void ForEachTuple(Tuple&& tuple,
                                       Fn&& fn,
                                       std::index_sequence<I...>) {
        using Expander = int[];
        (void)Expander{0, ((void)fn(std::get<I>(std::forward<Tuple>(tuple))), 0)...};
    }

    template <typename Fn, typename Tuple>
    inline constexpr void ForEachTuple(Tuple&& tuple, Fn&& fn) {
        ForEachTuple(
                std::forward<Tuple>(tuple), std::forward<Fn>(fn),
                std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
    }

    template <typename T>
    struct is_field_pointer : std::false_type {};

    template <typename C, typename T>
    struct is_field_pointer<T C::*> : std::true_type {};

    template <typename T>
    constexpr auto is_field_pointer_v = is_field_pointer<T>::value;

}  

template <typename T>
inline constexpr auto StructSchema() {
    return std::make_tuple();
}

#define DEFINE_STRUCT_SCHEMA(Struct, ...)        \
  template <>                                    \
  inline constexpr auto StructSchema<Struct>() { \
    using _Struct = Struct;                      \
    return std::make_tuple(__VA_ARGS__);         \
  }

#define DEFINE_STRUCT_FIELD(StructField, FieldName) \
  std::make_tuple(&_Struct::StructField, FieldName)

template <typename T, typename Fn>
inline constexpr void ForEachField(T&& value, Fn&& fn) {
    constexpr auto struct_schema = StructSchema<std::decay_t<T>>();
    static_assert(std::tuple_size<decltype(struct_schema)>::value != 0,
                  "");

    detail::ForEachTuple(struct_schema, [&value, &fn](auto&& field_schema) {
        using FieldSchema = std::decay_t<decltype(field_schema)>;
        static_assert(
                std::tuple_size<FieldSchema>::value >= 2 &&
                detail::is_field_pointer_v<std::tuple_element_t<0, FieldSchema>>,"");

        fn(value.*(std::get<0>(std::forward<decltype(field_schema)>(field_schema))),
           std::get<1>(std::forward<decltype(field_schema)>(field_schema)));
    });
}


#endif //UNTITLED_STATICREFLECTION_H
struct SimpleStruct {
    bool bool_;
    int int_;
    double double_;
    std::string string_;
};

DEFINE_STRUCT_SCHEMA(SimpleStruct,
                     DEFINE_STRUCT_FIELD(bool_, "bool"),
                     DEFINE_STRUCT_FIELD(int_, "int"),
                     DEFINE_STRUCT_FIELD(double_, "double"),
                     DEFINE_STRUCT_FIELD(string_, "string"));

struct GenericFunctor {
    template <typename Field, typename Name>
    void operator()(Field&& field, Name&& name) {
        std::cout << std::boolalpha << std::fixed << name << ": " << field
                  << std::endl;
    }
};

namespace {

    template <class... Fs>
    struct overload_set;

    template <class F1, class... Fs>
    struct overload_set<F1, Fs...> : F1, overload_set<Fs...>::type {
        typedef overload_set type;

        overload_set(F1 head, Fs... tail)
                : F1(head), overload_set<Fs...>::type(tail...) {}

        using F1::operator();
        using overload_set<Fs...>::type::operator();
    };

    template <class F>
    struct overload_set<F> : F {
        typedef F type;
        using F::operator();
    };

    template <class... Fs>
    typename overload_set<Fs...>::type overload(Fs... x) {
        return overload_set<Fs...>(x...);
    }

}

int main() {
    ForEachField(SimpleStruct{true, 1, 1.0, "static reflection"},
                 [](auto&& field, auto&& name) {
                     std::cout << std::boolalpha << std::fixed << name << ": "
                               << field << std::endl;
                 });

    ForEachField(SimpleStruct{true, 1, 1.0, "static reflection"},
                 GenericFunctor{});

    ForEachField(SimpleStruct{true, 1, 1.0, "static reflection"},
                 overload(
                         [](bool field, const char* name) {
                             std::cout << "b " << std::boolalpha << name << ": "
                                       << field << std::endl;
                         },
                         [](int field, const char* name) {
                             std::cout << "i " << name << ": " << field << std::endl;
                         },
                         [](double field, const char* name) {
                             std::cout << "d " << std::fixed << name << ": " << field
                                       << std::endl;
                         },
                         [](const std::string& field, const char* name) {
                             std::cout << "s " << name << ": " << field.c_str()
                                       << std::endl;
                         }));
    return 0;
}
动态反射静态反射
使用难度难)需要 编写注册代码,调用 RegisterField 动态绑定字段信息(易)可以通过 声明式 的方法,静态定义字段信息
运行时开销(有)需要动态构造 converter 对象,需要通过 虚函数表 (virtual table) 实现面向对象的多态(无)编译时 静态展开代码,和直接手写一样
可复用性(差)每个 converter 对象绑定了各个 字段类型 的具体 映射方法;如果需要进行不同转换操作,则需要另外创建 converter 对象(好)在调用 ForEachField 时,映射方法 作为参数传入;利用 编译时多态 的机制,为不同的 字段类型 选择合适的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值