Я унаследовал Таблица данных Шлюз реализации, и я пытаюсь преобразовать некоторые ошибки времени выполнения в ошибки времени компиляции. Существует простое взаимно однозначное сопоставление между таблицей и классом, но не все операции 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;
};
Я хотел бы переключиться на смешанный тип реализации, чтобы каждый постоянный тип имел связанный объектный менеджер, созданный только из операций, которые действительны для этого типа объекта. Я обнаружил, что если я разобью функции 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;
Я хотел бы добраться до точки, где я могу генерировать эти типы object_manager во время компиляции из boost :: mpl :: vector, чтобы я мог иметь класс признаков для персистентного типа, который перечисляет допустимые операции.
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 и т. Д.) С реальными классами миксина тривиально, но я бьюсь над тем, как воссоздать типы, показанные в третьем блоке кода. У меня есть смутное представление о том, что boost :: mpl :: inherit_linearly сыграет свою роль, но мне пока не ясно, как все части сочетаются друг с другом.
Я должен упомянуть, что у меня есть доступ к относительно современному Boost, но не к C ++ 11.
Задача ещё не решена.
Других решений пока нет …