Как вызвать конкретный метод шаблона в классе детей (наследование с помощью CRTP-решения) - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть шаблон, похожий на Стратегию, где интерфейс Стратегии IFilter , Контекст Контекст класс, Filter1 , Filter2 ..и т. д. - это конкретные стратегии, CommonFilter является промежуточным звеном между стратегией и конкретной стратегией для некоторых операций обслуживания.

Структура наследования IFilter> CommonFilter> Specific_filters

У меня много классов фильтров, каждый фильтр может работать с различным типом массива числовых данных (int, int16,uint16, float, double ... и т. д.).Фильтры отличаются друг от друга, но внутри одного фильтра они одинаково работают на разных числовых типах.

Каждый фильтр получает на входной структуре - FilterMetaData , которая имеет: источник данных, тип данныхи размер данных.На выходе фильтр создает ту же структуру. FilterMetaData apply (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;Так что должна быть цепочка фильтров.Эта цепочка будет вызываться несколько раз;

Так что я не знаю, как вызывать фильтр с определенным типом, я не хочу устанавливать условие типа в каждом фильтре.

psЯ использую старый компилятор gcc 4.4.7, совместимый только с ранним c ++ 0x

pps Добавлен конкретный пример фильтра.Так как я могу автоматически вызывать применять в конкретном фильтре на основе числового типа.Если есть Filter1, Filter2 ... FilterN.Я не хочу проверять тип в каждом фильтре, я хочу сделать это один раз.Все цепочки фильтров должны вызываться один за другим.
Например,

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 Ответ

0 голосов
/ 18 сентября 2018

Благодаря этому сообщению "Наследование методов шаблона" (с использованием 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
...