Как вызвать конкретный метод шаблона в классе детей (наследование с помощью CRTP -решения)
У меня есть шаблон, подобный стратегии, где интерфейсом стратегии является IFilter, Context - это класс Context, Filter1, Filter2... и т. Д. - это Concrete Strategies, CommonFilter - это промежуточный слой между Strategy и Concrete Strategy для некоторых операций сервиса.
Структура наследования IFilter > CommonFilter > Specific_filters
У меня много классов фильтров, каждый фильтр может работать с различными типами массивов числовых данных (int, int16, uint16, float, double ... и т. Д.). Фильтры отличаются друг от друга, но внутри одного фильтра они одинаково работают на разных числовых типах.
Каждый фильтр получает на входе структуру - FilterMetaData, которая имеет: источник данных, тип данных и размер данных. На выходе фильтр создает ту же структуру. Применить FilterMetaData (const FilterMetaData metaData); Фильтр может принимать, например, данные uint16 и выводить uint16 для другого фильтра в цепочке.
Фильтры имеют базовый класс CommonFilter, который проверяет FilterMetaData. CommonFilter реализует интерфейс IFilter;
У меня есть список фильтров QList m_filters; Я хочу перебрать объекты фильтра, как это
class Context {...
for(auto filter : m_filters)
{
filterMetaData = filter->apply(filterMetaData);//parse type of previous filter and work with it
}
И я хочу, чтобы тип данных фильтра выбирался автоматически из поля структуры FilterMetaData:: typeOfData; Так что должна быть цепочка фильтров. Эта цепочка будет вызываться несколько раз;
Так что я не знаю, как вызвать фильтр с определенным типом, я не хочу, чтобы условие типа в каждом фильтре.
я использую старый компилятор gcc 4.4.7, совместимый только с ранним C++ 0x
pps добавил конкретный пример фильтра. Итак, как я могу автоматически вызывать применить
например
data in/out uint16 array uint16 array uint8 array ...
--------->Filter1--------->Filter2--------->Filter3----->...
class IFilter
{
public:
virtual ~IFilter(){}
// do filtration
virtual FilterMetaData apply(const FilterMetaData metaData) = 0;
};
enum TypeOfData
{
Uint_8,
Uint_16,
Float
...
};
class FilterMetaData
{
public:
void *dataIn;
TypeOfData typeOfData;
int numOfElements;
};
class CommonFilter : public QObject, public IFilter
{
Q_OBJECT
Q_INTERFACES(IFilter)
public:
explicit CommonFilter(QObject *parent = nullptr);
public:
virtual FilterMetaData apply(const FilterMetaData metaData) override = 0;
const FilterMetaData metaData() const;
protected:
bool applyMetaData(const FilterMetaData metaData);
private:
FilterMetaData m_metaData;
};
Пример фильтра
class Filter1 : public CommonFilter
{
Q_OBJECT
public:
explicit Filter1(QObject *parent = nullptr);
//common type
FilterMetaData apply(const FilterMetaData metaData) override;
//filtration for specific type
template<typename T>
FilterMetaData apply(const FilterMetaData metaData);
};
1 ответ
Благодаря этому посту "Наследование методов шаблона" (Использование CRTP)
Я изменил свой код, чтобы соответствовать шаблону CRTP, теперь он работает так, как я хотел.
Вот решение:
class IFilter
{
public:
virtual ~IFilter(){}
virtual FilterMetaData apply(const FilterMetaData metaData) = 0;
};
Q_DECLARE_INTERFACE(IFilter, "IFilter")
template<class T>
class CommonFilterTest : public IFilter
{
public:
template<typename A = int>
void doSomething(TypeOfData typeOfData)
{
qDebug() << "SomeClass doSomething";
if(typeOfData == TypeOfData::Uint_16)
static_cast<T*>(this)->doSomething<int>();
else if(typeOfData == TypeOfData::Uint_8)
static_cast<T*>(this)->doSomething<quint8>();
else if(typeOfData == TypeOfData::Float)
static_cast<T*>(this)->doSomething<float>();
}
// IFilter interface
public:
virtual FilterMetaData apply(const FilterMetaData metaData) {}
};
class ConcreteFilter1 : public CommonFilterTest<ConcreteFilter1>
{
public:
template<typename A>
void doSomething()
{
float testNumber = 600.999;
qDebug() << typeid(A).name() << "TheFirstType doSomething" << (A) testNumber;
}
FilterMetaData apply(const FilterMetaData metaData)
{
((CommonFilterTest<ConcreteFilter1>*)this)->doSomething<int>(metaData.typeOfData);
return metaData;
}
};
Окончательно выполнить:
CommonFilterTest<ConcreteFilter1> * filter1 = new ConcreteFilter1();
FilterMetaData metaData;
metaData.typeOfData = TypeOfData::Uint_16;
filter1->apply(metaData); // we can do it in loop for different filters