Здравствуйте.
Изучаю С++ и пишу библиотеку ModBus. Прошу полезного совета у Гуру по изменению архитектуры в целом или ответить на конкретные вопросы в конце.
Я хочу с помощью шаблонов классов автоматически помещать любые пользовательские данные в нужные таблицы данных ModBus с возвращением указателей на них.
class AlarmData
{
bool isAlarm;
bool isCountActivate;
};
class MeintenanceData
{
unsigned short Id;
float Rate;
};
AlarmData *AlarmData_Alarm1_ptr = InputBits<AlarmData>::Add();
AlarmData *AlarmData_Alarm2_ptr = InputBits<AlarmData>::Add();
MeintenanceData *AlarmData_Meintenance1_ptr = InputRegs<MeintenanceData>::Add();
MeintenanceData *AlarmData_Meintenance2_ptr = InputRegs<MeintenanceData>::Add();
Таким образом для класса AlarmData создается свой класс регистрирующий все объекты типа AlarmData. Тоже происходит и для класса MeintenanceData. Дискретные данные для аварий помещаются в таблицу дискретных данных, а данные 16 бит помещаются в таблицу регистров модбас.
Так же с помощью статического метода шаблонного класса можно задать адрес для созданной области объектов в таблице ModBus.
InputBits<AlarmData>::AddresSet(100);
InputRegs<MeintenanceData>::AddresSet(200);
Таким образом будут формироваться таблицы данных, доступ к которым будет осуществляться из вне сторонним устройством по интерфейсу RS485 и протоколу ModBus с заданием адреса внутри посылки, указанного в моей программе с помощью AddresSet.
В начале мной был создан базовый шаблон класса
template <typename T_DataType>
class ModBusTables
{
protected:
static unsigned short Addres;
static unsigned short AreaSize;
T_DataType *AreaData_ptr;
ModBusTables();
public:
static void AddresSet(unsigned short ModBusAddres);
};
где
static unsigned short Addres - Адрес области в таблице протокола Модбас
static unsigned short AreaSize - Размер объектов в области
T_DataType *AreaData_ptr - Тип для приведения указателя.
Так как в ModBus фактически существует только два типа данных дискретные и ячейки по 16 бит, то в параметрах данного шаблона будет либо bool либо unsigned short. Таким образом AreaData_ptr - это указатель на тип данных конкретной таблицы ModBus, чтобы можно было путешествовать по любым данным пользователя с помощью единого указателя.
Далее я решил унаследовать от базового шаблона для каждой таблицы ModBus свой класс. Это таблицы регистров и дискретных данных для входных и выходных параметров.
template <typename T> class InputBitsTable: public ModBusTables<T>{};
template <typename T> class InputRegsTable: public ModBusTables<T>{};
template <typename T> class OutputBitsTable:public ModBusTables<T>{};
template <typename T> class OutputRegsTable:public ModBusTables<T>{};
Сделал я это для того, чтобы от каждого из этих классов наследовать другой класс, таким образом реализуя помещение наследованного класса в таблицу родительского.
Теперь приведу код шаблонного класса, который наследуется от одного из классов выше и расскажу в чем заключается вопрос.
template <class T_DataStruct, class Specialization> class ModBusTable;
template <class T_DataStruct, typename T_DataType, template<typename> class TT_Table>
class ModBusTable<T_DataStruct, TT_Table<T_DataType> > : public TT_Table<T_DataType>
{
private:
T_DataStruct AreaData;
public:
static T_DataStruct *Add()
{
ModBusTable *ModBusArea_ptr = new ModBusTable();
T_DataStruct *Instance_Ptr = &ModBusArea_ptr->AreaData;
ModBusTable<T_DataStruct, TT_Table<T_DataType> >::AreaSize = sizeof(ModBusArea_ptr->AreaData);
ModBusArea_ptr->AreaData_ptr = (T_DataType *)Instance_Ptr;
return Instance_Ptr;
}
};
Главная задача данного шаблонного класса - создать свой объект в статическом методе, зарегистрировать его в классе и возвратить указатель на данные пользовательского типа, а так же преобразовать этот указатель в указатель AreaData_ptr объявленный в родительском классе, чтобы с любыми пользовательскими типами можно было работать через указатель на bool или unsigned short.
Теперь сам вопрос. Для того, чтобы не вбивать много параметров в шаблон для регистрирования пользовательских данных в конкретной таблице ModBus, я применил наследование.
template <class T> class InputBits: public ModBusTable<T, InputBitsTable<bool> > {};
template <class T> class InputRegs: public ModBusTable<T, InputRegsTable<unsigned short> > {};
template <class T> class OutputBits: public ModBusTable<T, OutputBitsTable<bool> > {};
template <class T> class OutputRegs: public ModBusTable<T, OutputRegsTable<unsigned short> > {};
Существует ли способ заменить наследование в данном случае на что-то похожее на alias template в С++11, чтобы создавать шаблон класса с новым именем InputBits по шаблону ModBusTable? Так, чтобы работало выражение
InputBits<AlarmData>::Add()
Приму любые советы по изменению архитектуры реализации данной задачи. Большое спасибо за прочтение, внимание и ответы!
Для стандарта C++11 и новее можно было бы записать
template<class A, class B>
struct Base{};
template<class A>
using WrapperFirst = Base<A, int>;
template<class A>
using WrapperSecond = Base<A, double>;
int main() {
WrapperFirst<int> a;
WrapperSecond<int> b;
return 0;
}
Полного аналога alias template в C++03 построить не получится.
Можно использовать шаблон структуры для частичного задания параметров базового шаблона.
template<class A, class B>
struct Base{};
template<class A>
struct Wrapper
{
typedef Base<A, int> first;
typedef Base<A, double> second;
};
int main() {
Wrapper<int>::first a;
Wrapper<int>::second b;
return 0;
}
Сборка персонального компьютера от Artline: умный выбор для современных пользователей