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 时,映射方法 作为参数传入;利用 编译时多态 的机制,为不同的 字段类型 选择合适的操作 |