我继承了Table Data Gateway实现,并且正在尝试将一些运行时错误转换为编译时错误。表和类之间存在简单的一对一映射,但并非所有 CRUD 操作对所有类型都有意义。有一个单一的“经理”类模板(以简化形式)看起来像
template <typename T>
class object_manager
{
public:
void create(const T&){ /* SQL CREATE */ }
void update(const T&){ /* SQL UPDATE */ }
void del(const T&){ /* SQL DELETE */ }
template <OutIt> OutIt read(OutIt) const {/* SQL SELECT */}
private:
some_db_connection& m_db;
};
我想切换到混合类型的实现,这样每个持久类型都有一个关联的 object_manager,它仅由对该对象类型有效的操作构建而成。我发现如果我因此将 CRUD 函数分解为它们自己的类
template <typename T>
class object_manager
{
public:
typedef T object_type;
protected:
some_db_connection& m_db;
};
template <typename Base>
class create_mixin : public Base
{
public:
typedef Base::object_type object_type;
void create(const object_type&) { /* sql INSERT */ }
};
template <typename Base>
class read_mixin : public Base
{
public:
typedef Base::object_type object_type;
template <OutIt> OutIt read(OutIt) const {/* SQL SELECT */}
};
template <typename Base>
class update_mixin : public Base
{
public:
typedef Base::object_type object_type;
void update(const object_type&) {/* SQL UPDATE*/}
};
template <typename Base>
class delete_mixin : public Base
{
public:
typedef Base::object_type object_type;
void del(const object_type&) {/* SQL DELETE*/}
};
然后我能够生成一个只有有效操作的类型,从而在编译类型中找到不正确的函数调用(例如尝试更新不可变类型)
//read-only
read_mixin<object_manager<some_persistent_type>> read_only_mgr;
//un-deletable
create_mixin<read_mixin<update_mixin<object_manager<some_persistent_type>>>> undeletable_mgr;
我希望能够在编译时从 boost::mpl::vector 生成这些 object_manager 类型,这样我就可以有一个用于列出有效操作的持久类型的特征类。
struct op_create;
struct op_read;
struct op_update;
struct op_delete;
template <typename T>
struct my_traits
{
typedef boost::mpl::vector<op_create, op_read, op_delete> valid_operations;
};
将一些符号名称(例如 op_read、op_create 等)映射到实际的 mixin 类是微不足道的,但我正在努力的是如何重新创建第三个代码块中显示的类型。我有一个模糊的概念,即 boost::mpl::inherit_linearly 将发挥作用,但我还不清楚所有部分是如何组合在一起的。
我应该提一下,我可以使用相对现代的 Boost,但不能使用 c++11。