如何在子 class 中调用特定的模板方法(使用 CRTP 继承 - 解决方案)
How to invoke specific template method in children class (inheritance with CRTP - solution)
我有一个类似于模式的策略,其中 Strategy 接口是 IFilter,上下文是 Context class,Filter1、Filter2...等都是Concrete Strategies,CommonFilter是Strategy和Concrete Strategy之间的中间层,用于一些服务操作。
继承结构IFilter > CommonFilter > Specific_filters
我有很多过滤器 classes,每个过滤器都可以处理不同类型的数字数据数组(int、int16、uint16、float、double ... 等)。过滤器彼此不同,但在一个过滤器内,它们对不同的数字类型同样有效。
每个过滤器在输入结构中接收 - FilterMetaData,它具有:数据源、数据类型和数据大小。在输出端,过滤器产生相同的结构。 FilterMetaData 应用(const FilterMetaData 元数据);
过滤器可以采取例如uint16 数据,并输出 uint16,用于链中的另一个过滤器。
过滤器具有基础 class 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。我使用仅与早期 c++0x
兼容的旧 gcc 4.4.7 编译器
p.p.s 添加了具体的过滤器示例。那么我如何在基于数字类型的特定过滤器中自动调用 apply< T>。如果有 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);
};
多亏了这个post"Inheriting template methods" (Using 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
我有一个类似于模式的策略,其中 Strategy 接口是 IFilter,上下文是 Context class,Filter1、Filter2...等都是Concrete Strategies,CommonFilter是Strategy和Concrete Strategy之间的中间层,用于一些服务操作。
继承结构IFilter > CommonFilter > Specific_filters
我有很多过滤器 classes,每个过滤器都可以处理不同类型的数字数据数组(int、int16、uint16、float、double ... 等)。过滤器彼此不同,但在一个过滤器内,它们对不同的数字类型同样有效。
每个过滤器在输入结构中接收 - FilterMetaData,它具有:数据源、数据类型和数据大小。在输出端,过滤器产生相同的结构。 FilterMetaData 应用(const FilterMetaData 元数据); 过滤器可以采取例如uint16 数据,并输出 uint16,用于链中的另一个过滤器。
过滤器具有基础 class 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。我使用仅与早期 c++0x
兼容的旧 gcc 4.4.7 编译器p.p.s 添加了具体的过滤器示例。那么我如何在基于数字类型的特定过滤器中自动调用 apply< T>。如果有 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);
};
多亏了这个post"Inheriting template methods" (Using 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