My actual idea is not compiling due to C++ language limitation (templated virtual functions are not supported). Maybe some of you have some design recommendations for the following code snippet.
I want to run different algorithms on different types of inputs. For example I have as input an integral image and an grayscale image. The integral image needs 32 bit for a pixel and my grayscale image needs 8 bit (just as an example). Therefore, I have two channels: CChannel<uint8>
and CChannel<uint32>
Since I could have multiple channels for a single image, I store the channels in a vector, std::vector<CChannelBase*>
... That's the justification of the class CChannelBase
.
class CChannelBase
{
public:
virtual ~CChannelBase( void ) = 0;
};
template <class ValueType>
class CChannel : public CChannelBase
{
public:
typedef ValueType value_type_t;
Channel(): m_data_p(0) {}
void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
const ValueType getData( void ) { return m_data_p; }
private:
ValueType* m_data_p;
};
All my algorithms implement an interface and must be compatible with each image channel.
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() = 0;
template <class ValueType>
virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
class CAlgorithmA : IAlgorithmInterface
{
CAlgorithmA() {...};
~CAlgorithmA() {...};
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};
class CAlgorithmB : IAlgorithmInterface
{
CAlgorithmB() {...};
~CAlgorithmB() {...};
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};
Of course this code is not compiling since we have virtual template functions. Anyway, I am looking for a nice design to overcome this problem. A solution is that all classes (IAlgorithmInterface
, CAlgorithmA
, CAlgorithmB
) are templatized which is a thing I do not want to do. I saw a few posts here, where the visitor pattern is recommended. But to be honest, I do not see how to use it in my case.
Not sure if this solves all of your problems, since there isn't much to go on as to what you actually want this code to actually "do", but with a little bit of shuffling, it compiles:
typedef float float32_t;
class CChannelBase
{
public:
virtual ~CChannelBase( void ) = 0;
};
template <class ValueType>
class CChannel : public CChannelBase
{
public:
typedef ValueType value_type_t;
CChannel(): m_data_p(0) {}
void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
const ValueType getData( void ) { return m_data_p; }
private:
ValueType* m_data_p;
};
template <class ValueType>
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() = 0;
virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
template <class ValueType>
class CAlgorithmA : IAlgorithmInterface<ValueType>
{
CAlgorithmA() {};
~CAlgorithmA() {};
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};
template <class ValueType>
class CAlgorithmB : IAlgorithmInterface<ValueType>
{
CAlgorithmB() {};
~CAlgorithmB() {};
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};
int main()
{
}
In essence, just move the templace<class ValueType> out a level, to the class, and add it to the
IAloorithmInferface` inheritance.
I fully expect to be told that this won't work for what you are trying to do, but there is no example of what you actually want these classes to do, so I can't really tell if it works or not.
Okay, this is kind of convoluted, but you have kind of a convoluted requirement. IAlgorithmInterface
can have a template method, but it can't be virtual. You can create an intermediate class that itself is a template virtually derived from IAlgorithmInterface
which proxies the template method to some code that does the real work. The real work is provided in a template parameter fed to templated derivation of IAlgorithmInterface
.
This scheme allows the template method of IAlgorithmInterface
to dispatch to the appropriate derived class via a downcast.
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() {}
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
template <class ValueType, typename RealWork>
class IAlgorithmTemplate : virtual public IAlgorithmInterface
{
public:
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
RealWork()(f_channel_p, f_result_r);
}
};
template <class ValueType>
void IAlgorithmInterface::doWork(const CChannel<ValueType>* f_channel_p,
float32_t& f_result_r)
{
IAlgorithmTemplate<ValueType> *alg
= dynamic_cast<IAlgorithmTemplate<ValueType>*>(this);
alg->doWork(f_channel_p, f_result_r);
}
Now, via multiple inheritance, we can create the actual interface that algorithm implementations would use. Because IAlgorithmTemplate
uses virtual inheritance, there is only one IAlgorithmInterface
instance. So to support ValueTypeNew
, you would add a IAlgorithmTempalte<ValueTypeNew>
to the inheritance list.
template <template <class> class RealWork>
class IAlgorithmBase :
public IAlgorithmTemplate<ValueTypeOne, RealWork<ValueTypeOne> >,
public IAlgorithmTemplate<ValueTypeTwo, RealWork<ValueTypeTwo> >,
//...
public IAlgorithmTemplate<ValueTypeLast, RealWork<ValueTypeLast> > {
};
Finally, each algorithm derives from IAlgorithmBase
, and implements the RealWork
as a template.
template <class ValueType>
struct RealAlgorithmA {
void operator () (const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
//...
}
};
class CAlgorithmA : public IAlgorithmBase<RealAlgorithmA>
{
public:
CAlgorithmA() {...}
~CAlgorithmA() {...}
};
My actual idea is not compiling due to C++ language limitation (templated virtual functions are not supported). Maybe some of you have some design recommendations for the following code snippet.
I want to run different algorithms on different types of inputs. For example I have as input an integral image and an grayscale image. The integral image needs 32 bit for a pixel and my grayscale image needs 8 bit (just as an example). Therefore, I have two channels: CChannel<uint8>
and CChannel<uint32>
Since I could have multiple channels for a single image, I store the channels in a vector, std::vector<CChannelBase*>
... That's the justification of the class CChannelBase
.
class CChannelBase
{
public:
virtual ~CChannelBase( void ) = 0;
};
template <class ValueType>
class CChannel : public CChannelBase
{
public:
typedef ValueType value_type_t;
Channel(): m_data_p(0) {}
void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
const ValueType getData( void ) { return m_data_p; }
private:
ValueType* m_data_p;
};
All my algorithms implement an interface and must be compatible with each image channel.
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() = 0;
template <class ValueType>
virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
class CAlgorithmA : IAlgorithmInterface
{
CAlgorithmA() {...};
~CAlgorithmA() {...};
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};
class CAlgorithmB : IAlgorithmInterface
{
CAlgorithmB() {...};
~CAlgorithmB() {...};
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {...};
};
Of course this code is not compiling since we have virtual template functions. Anyway, I am looking for a nice design to overcome this problem. A solution is that all classes (IAlgorithmInterface
, CAlgorithmA
, CAlgorithmB
) are templatized which is a thing I do not want to do. I saw a few posts here, where the visitor pattern is recommended. But to be honest, I do not see how to use it in my case.
Not sure if this solves all of your problems, since there isn't much to go on as to what you actually want this code to actually "do", but with a little bit of shuffling, it compiles:
typedef float float32_t;
class CChannelBase
{
public:
virtual ~CChannelBase( void ) = 0;
};
template <class ValueType>
class CChannel : public CChannelBase
{
public:
typedef ValueType value_type_t;
CChannel(): m_data_p(0) {}
void setData(ValueType* f_data_p) { m_data_p = f_data_p; }
const ValueType getData( void ) { return m_data_p; }
private:
ValueType* m_data_p;
};
template <class ValueType>
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() = 0;
virtual void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
template <class ValueType>
class CAlgorithmA : IAlgorithmInterface<ValueType>
{
CAlgorithmA() {};
~CAlgorithmA() {};
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};
template <class ValueType>
class CAlgorithmB : IAlgorithmInterface<ValueType>
{
CAlgorithmB() {};
~CAlgorithmB() {};
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {};
};
int main()
{
}
In essence, just move the templace<class ValueType> out a level, to the class, and add it to the
IAloorithmInferface` inheritance.
I fully expect to be told that this won't work for what you are trying to do, but there is no example of what you actually want these classes to do, so I can't really tell if it works or not.
Okay, this is kind of convoluted, but you have kind of a convoluted requirement. IAlgorithmInterface
can have a template method, but it can't be virtual. You can create an intermediate class that itself is a template virtually derived from IAlgorithmInterface
which proxies the template method to some code that does the real work. The real work is provided in a template parameter fed to templated derivation of IAlgorithmInterface
.
This scheme allows the template method of IAlgorithmInterface
to dispatch to the appropriate derived class via a downcast.
class IAlgorithmInterface
{
public:
virtual ~IAlgorithmInterface() {}
template <class ValueType>
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r);
};
template <class ValueType, typename RealWork>
class IAlgorithmTemplate : virtual public IAlgorithmInterface
{
public:
void doWork(const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
RealWork()(f_channel_p, f_result_r);
}
};
template <class ValueType>
void IAlgorithmInterface::doWork(const CChannel<ValueType>* f_channel_p,
float32_t& f_result_r)
{
IAlgorithmTemplate<ValueType> *alg
= dynamic_cast<IAlgorithmTemplate<ValueType>*>(this);
alg->doWork(f_channel_p, f_result_r);
}
Now, via multiple inheritance, we can create the actual interface that algorithm implementations would use. Because IAlgorithmTemplate
uses virtual inheritance, there is only one IAlgorithmInterface
instance. So to support ValueTypeNew
, you would add a IAlgorithmTempalte<ValueTypeNew>
to the inheritance list.
template <template <class> class RealWork>
class IAlgorithmBase :
public IAlgorithmTemplate<ValueTypeOne, RealWork<ValueTypeOne> >,
public IAlgorithmTemplate<ValueTypeTwo, RealWork<ValueTypeTwo> >,
//...
public IAlgorithmTemplate<ValueTypeLast, RealWork<ValueTypeLast> > {
};
Finally, each algorithm derives from IAlgorithmBase
, and implements the RealWork
as a template.
template <class ValueType>
struct RealAlgorithmA {
void operator () (const CChannel<ValueType>* f_channel_p, float32_t& f_result_r) {
//...
}
};
class CAlgorithmA : public IAlgorithmBase<RealAlgorithmA>
{
public:
CAlgorithmA() {...}
~CAlgorithmA() {...}
};
0 commentaires:
Enregistrer un commentaire