增加反射C++并不出奇困难,但它确实需要的模板类型推演和一些精心策划的一个相当不错的知识。
在此工作示例我已经开始为您服务。该框架支持将成员写入“语句”类(对数据库准备语句进行建模)。
类似的技术可用于打造出来的SQL生成CRUD。
毫无疑问,已经为你做这个图书馆...
#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <utility>
using namespace std;
struct statement
{
void setString(int index, const std::string& value)
{
std::cout << "setting index " << index << " to value " << std::quoted(value) << std::endl;
}
};
struct BaseOrm
{
virtual void serialise(statement& stmt) const = 0;
};
template<class Class>
struct class_tag {
using type = Class;
};
template<const char* Name>
struct name_tag {
static constexpr const char* name() { return Name; }
};
namespace detail {
struct reflection_item_concept
{
virtual const std::string& name() const = 0;
virtual std::string to_archive_string(const void* object) const = 0;
virtual void from_archive_string(void* object, const std::string& as) const = 0;
};
template<class T>
std::string to_archive_string_impl(const T& val) {
return std::to_string(val);
}
const std::string& to_archive_string_impl(const std::string& s) {
return s;
}
template<class NameTag, class Class, class Type>
struct reflection_item : reflection_item_concept
{
reflection_item(Type Class::* mfp) : mfp(mfp) {}
static const class_tag<Class> class_info() { return {}; };
static const char* raw_name() { return NameTag::name(); };
// concept implementation
const std::string& name() const override {
static const std::string s = raw_name();
return s;
}
std::string to_archive_string(const void* object) const override
{
auto& val = (*reinterpret_cast<const Class*>(object)).*mfp;
return to_archive_string_impl(val);
}
void from_archive_string(void* item, const std::string& as) const override
{
// similar mechanism here
}
Type Class::* mfp;
};
}
template<class NameTag, class Class, class Type>
constexpr auto reflection_item(NameTag, Type Class::* mp)
{
return detail::reflection_item<NameTag, Class, Type> { mp };
}
struct class_reflection_concept
{
virtual void serialise(const void* object, statement& stmt) const = 0;
};
namespace detail {
template<class ClassTag, class...ReflectionItems>
struct reflection_impl : class_reflection_concept
{
reflection_impl(ReflectionItems...refs)
: _reflectors(std::make_tuple(refs...))
{}
template<std::size_t...Is>
void serialise_impl(std::index_sequence<Is...>, const void* object,
statement& stmt) const
{
using expand = int[];
void(expand{
0,
(stmt.setString(Is + 1, std::get<Is>(_reflectors).to_archive_string(object)),0)...
});
}
void serialise(const void* object, statement& stmt) const override
{
serialise_impl(std::make_index_sequence<sizeof...(ReflectionItems)>(),
object, stmt);
}
std::tuple<ReflectionItems...> _reflectors;
};
}
template<class ClassTag, class...ReflectionItems>
auto& make_reflection(ClassTag tag, ReflectionItems...items)
{
static const detail::reflection_impl<ClassTag, ReflectionItems...> _ { items... };
return _;
}
const char txt_username[] = "username";
const char txt_email[] = "email";
const char txt_x[] = "x";
class userProfile: public BaseOrm
{
public:
string username = "test username";
string email = "[email protected]";
int x = 10;
// implement serialisation
void serialise(statement& stmt) const override
{
reflection.serialise(this, stmt);
}
static const class_reflection_concept& reflection;
};
const class_reflection_concept& userProfile::reflection =
make_reflection(class_tag<userProfile>(),
reflection_item(name_tag<txt_username>(), &userProfile::username),
reflection_item(name_tag<txt_email>(), &userProfile::email),
reflection_item(name_tag<txt_x>(), &userProfile::x));
int main()
{
userProfile x;
statement stmt;
x.serialise(stmt);
}
预计业绩:
setting index 1 to value "test username"
setting index 2 to value "[email protected]"
setting index 3 to value "10"
您可以通过'userProfile'作为模板参数'BaseOrm'。 –
您应该在自定义类中重载/覆盖'save'和'migrate'函数,并在合适的位置调用相应函数的基本版本。 – Arunmu
@πάνταῥεῖ如果你不介意,请给我一个例子:) –