gpt4 book ai didi

c++ - 在 C++ 中访问类中的字段和类型列表

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:03:49 28 4
gpt4 key购买 nike

您好,我正在尝试用 C++ 为一个项目创建一个简单的 ORM。对于这个例子,假设一个简单的类为

class userProfile: public BaseOrm
{
public:
string username;
string email;
};

现在 base orm 有一个方法 save() 和 migrate()。我想要的是当一个人调用 migrate() 所有模式时,在这种情况下,用户名和电子邮件被填充为数据库表并保存在数据库中。

我遇到的问题是如何获取类中定义的所有字段,如本例中的 usernameemail 以及类型、字符串在这种情况下。任何帮助将不胜感激。

我知道在 C++ 中没有反射,所以我实际上并不关心变量名,而是更关心变量的数量以及将它们映射到 DB 的类型。

最佳答案

将反射添加到 C++ 中并不难,但它确实需要对模板类型推导有相当丰富的知识和一些周密的计划。

在这个工作示例中,我已经为您做了一个开始。该框架支持将成员写出到“语句”类(模拟数据库准备语句)。

类似的技术可用于为 CRUD 构建 SQL 生成。

毫无疑问,已经有图书馆为您做这件事......

#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 = "noone@nowhere.com";
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 "noone@nowhere.com"
setting index 3 to value "10"

关于c++ - 在 C++ 中访问类中的字段和类型列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38217459/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com