Как вызвать определенный метод шаблона в дочернем классе (наследование с CRTP - решение)

У меня есть шаблон, похожий на стратегию, где интерфейс стратегии — IFilter, контекст — класс Context, 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; Так что это должна быть цепочка фильтров. Эта цепочка будет вызываться несколько раз;

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

p.s. я использую старый компилятор gcc 4.4.7, совместимый только с ранним С++ 0x

p.p.s добавлен конкретный пример фильтра. Итак, как я могу автоматически вызывать apply‹ T> в конкретном фильтре на основе числового типа. Если есть Фильтр1, Фильтр2... ФильтрN. Я не хочу проверять тип в каждом фильтре, я хочу сделать это один раз. Должна быть вызвана вся цепочка фильтров, один за другим.
например.

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);
};

person Storkur    schedule 17.09.2018    source источник
comment
В приведенном вами коде нет шаблонов. Если реализация вашей функции одинакова для каждого типа данных, используйте шаблоны. Если реализации различаются для каждого типа данных, вы можете использовать специализации шаблона, перегрузку функций или вариант шаблона стратегии?   -  person Yksisarvinen    schedule 17.09.2018
comment
Спасибо, я добавил некоторые подробности в раздел p.p.s. Я могу выбрать «Применить T» только в определенном классе, для каждого фильтра я хочу проверить тип, который может быть в базовом классе. Или, может быть, моя архитектура неверна   -  person Storkur    schedule 17.09.2018
comment
Похоже, вы можете захотеть сделать что-то с двойной отправкой.   -  person n. 1.8e9-where's-my-share m.    schedule 18.09.2018
comment
Спасибо, но у меня одинаковая реализация в одном фильтре для всех типов   -  person Storkur    schedule 19.09.2018


Ответы (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
person Storkur    schedule 18.09.2018