是吗?我不知道如何给C++添加反射。因此,在开发自己的解决方案之前,我需要先熟悉Boost概念。不管怎样,只要用宏标记成员,自动为其分配数据库列,那就太酷了。尽管在我的案例中,这显然是不必要的,但出于学习的目的,我可以尝试一下。自从我开始实施以来,我最初的
是吗?我不知道如何给C++添加反射。因此,在开发自己的解决方案之前,我需要先熟悉Boost概念。不管怎样,只要用宏标记成员,自动为其分配数据库列,那就太酷了。尽管在我的案例中,这显然是不必要的,但出于学习的目的,我可以尝试一下。自从我开始实施以来,我最初的,c++,sql,templates,types,struct,C++,Sql,Templates,Types,Struct,是吗?我不知道如何给C++添加反射。因此,在开发自己的解决方案之前,我需要先熟悉Boost概念。不管怎样,只要用宏标记成员,自动为其分配数据库列,那就太酷了。尽管在我的案例中,这显然是不必要的,但出于学习的目的,我可以尝试一下。自从我开始实施以来,我最初的问题,即需要一个数据结构来容纳一行,又出现了。我更新了问题,尽可能简明扼要地解释了这个问题。你能分享一下你的想法吗?@danijar:你现在所做的看起来很像性格特征。例如,在标准库中,std::basic_string的第二个模板参数默认为st
是吗?我不知道如何给C++添加反射。因此,在开发自己的解决方案之前,我需要先熟悉Boost概念。不管怎样,只要用宏标记成员,自动为其分配数据库列,那就太酷了。尽管在我的案例中,这显然是不必要的,但出于学习的目的,我可以尝试一下。自从我开始实施以来,我最初的问题,即需要一个数据结构来容纳一行,又出现了。我更新了问题,尽可能简明扼要地解释了这个问题。你能分享一下你的想法吗?@danijar:你现在所做的看起来很像性格特征。例如,在标准库中,
std::basic_string
的第二个模板参数默认为std::char_traits
。通过创建一个“基本”trait并为您需要存储的每个结构专门化它,trait可以提供(反)序列化方法,您可以通过模板代码访问它们(即,无需注册)。当然,它的美妙之处在于,您不需要实际修改Person
本身。感谢您指出这一点。我会查一查。这种特质起着注册的作用,所以我不知道什么更好。但traits似乎比我的转换函数方法更受欢迎,因此对其他人来说更具可读性。您还会将我的代码示例中的特征存储在列表中吗?列表的类型可以是std::unordered_map
。@danijar:不,一点也不。这就是这种特质的优点。编写DbTrait::Serialize
时,编译器知道在没有额外注册表的情况下使用DbTrait
的哪个专门化。因为没有额外的注册表,所以不需要基类和统一的函数签名。
struct Person
{
std::string Name;
int Age;
// more members that shouldn't be stored or loaded
// ...
};
// 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);
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
// ...
};
Data->Register<Person, std::string, int>(
[](Person *Instance) -> std::tuple<std::string, int>{ /* ... */ },
[](std::tuple<std::string, int> Row, Person *Instance) -> void{ /* ... */ }
);
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);
}
};
struct Person {
struct Name: Field<std::string> { static char const* N() { return "name"; } }
struct Age: Field<int> { static char const* N() { return "age"; } }
Name name;
Age age;
}; // struct Person
BOOST_FUSION_ADAPT_STRUCT(
Person,
(Name, name)
(Age, age))