我需要开发一个管理器,它接受 astruct
并将其成员存储到数据库行,并struct
再次用数据库行中的值填充 a。相同struct
的对象存储在同一个表中。这是我们的例子strcut
。
struct Person
{
std::string Name;
int Age;
// more members that shouldn't be stored or loaded
// ...
};
struct
我的目标是用一行将 s加载并存储到他们的表中。
// example for storing
unsigned int id = 42; // not hardcoded of course
Person paul = { "Paul", 8 }; // instantiate the struct
Data->Save<Person>(id, *paul); // table name is derived from template argument
// example for fetching
unsigned int id = 42;
Person paul;
Data->Load<Person>(id, *paul);
所有struct
s 都可以通过继承强制实现序列化和反序列化功能,或者我可以使用 Matthieu M. 在答案中建议的基于宏的反射。但我无法对struct
存储的 s 进行更改。所以我决定那些struct
s必须先注册,提供它们的序列化和反序列化功能。(我的意思是从实例转换为struct
数据库行对象,反之亦然。)
class Data
{
typedef std::function<row(T*) Serialization;
typedef std::function<void(row, T*) Deserialization;
typedef std::pair<Serialization, Deserialization> Registereds;
std::unordered_map<std::type_index, Registered> List;
public:
template <typename T>
Register<T>(std::function<row(T*) Serialize,
std::function<void(row, T*) Deserialize)
{
// create a table based on the template argument
std::string name = typeid(T).name();
// ...
// add conversion functions to the list
auto index = std::type_index(typeid(T));
List.insert(index, std::make_pair(Serialize, Deserialize));
}
// load and save functions shown above go here
// ...
};
您可能已经注意到row
我在此示例中使用的数据类型。这正是我的问题!对于每一struct
行,都包含不同类型的不同字段。那么我可以使用什么数据结构来保存一行?
我虽然关于使用某种std::tuple
. 例如,如果一个元组可以有字符串键,那是有可能的。然后,我必须完全模板化所有内容以使用不同struct
的 s。它可能看起来类似于下面的这个草稿。但是我必须知道如何在不使用指针的情况下将不同struct
s的转换函数存储在同一个中。List
void*
Data->Register<Person, std::string, int>(
[](Person *Instance) -> std::tuple<std::string, int>{ /* ... */ },
[](std::tuple<std::string, int> Row, Person *Instance) -> void{ /* ... */ }
);
如何表示数据库行对象?如果我的模板方法是一个好方法,我该如何模板化所有内容?
更新以响应马蒂厄 M. 的回答
您建议使用类型特征。这是我尝试过的。但我仍然不知道如何定义表示一行的类型。
性状
template <class T>
struct data_traits{ };
struct data_traits<Person>
{
struct row{ int Age; std::string Name; }; // right to do here?
row serialize(Person *Instance)
{
// ...
}
void deserialize(row Data, Person *Instance)
{
// ...
}
};
数据管理员
class Data
{
template <typename T>
void Load(uint64_t Id, T *Instance)
{
auto traits = data_traits<T>;
std::string query = "SELECT * FROM "
+ typeid(T).name()
+ " WHERE id = "
+ std::to_string(Id);
// fetch result from database
// ...
traits::row result;
// convert SQL result into type dependent row type
// but how to do that?
// ...
traits.deserialize(result, Instance);
}
};