绕过虚拟模板功能以实现希望的结果

时间:2013-08-27 21:56:25

标签: c++ templates design-patterns virtual

由于C ++语言限制,我的实际想法不是编译(不支持模板化虚函数)。也许你们中的一些人对以下代码片段有一些设计建议。

我想在不同类型的输入上运行不同的算法。例如,我输入了积分图像和灰度图像。对于像素,积分图像需要32位,而我的灰度图像需要8位(仅作为示例)。因此,我有两个渠道:CChannel<uint8>CChannel<uint32>

由于我可以为单个图像设置多个通道,因此我将通道存储在矢量std::vector<CChannelBase*>中......这就是类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;
};

我的所有算法都实现了一个接口,并且必须与每个图像通道兼容。

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

当然这个代码没有编译,因为我们有虚拟模板函数。无论如何,我正在寻找一个很好的设计来克服这个问题。一个解决方案是所有类(IAlgorithmInterfaceCAlgorithmACAlgorithmB)都是模板化的,这是我不想做的事情。我在这里看到了一些帖子,建议使用访问者模式。但说实话,我不知道如何在我的情况下使用它。

2 个答案:

答案 0 :(得分:0)

不确定这是否能解决您的所有问题,因为您实际上希望这些代码实际上“做”的内容并不多,但只需稍微改组,它就会编译:

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()
{
}

实质上,只需移动templace<class ValueType> out a level, to the class, and add it to the IAloorithmInferface`继承。

我完全希望被告知这对你要做的事情不起作用,但是没有你想要这些课程做什么的例子,所以我无法确定它是否有效。

答案 1 :(得分:0)

好的,这有点令人费解,但你有一种复杂的要求。 IAlgorithmInterface可以有模板方法,但不能是虚拟方法。您可以创建一个中间类,它本身是一个虚拟派生自IAlgorithmInterface的模板,它将模板方法代理到执行实际工作的某些代码。实际工作在模板参数中提供,该模板参数用于IAlgorithmInterface的模板推导。

此方案允许IAlgorithmInterface的模板方法通过向下转发分派到适当的派生类。

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

现在,通过多重继承,我们可以创建算法实现将使用的实际接口。由于IAlgorithmTemplate使用虚拟继承,因此只有一个IAlgorithmInterface实例。因此,要支持ValueTypeNew,您需要在继承列表中添加IAlgorithmTempalte<ValueTypeNew>

template <template <class> class RealWork>
class IAlgorithmBase :
    public IAlgorithmTemplate<ValueTypeOne, RealWork<ValueTypeOne> >,
    public IAlgorithmTemplate<ValueTypeTwo, RealWork<ValueTypeTwo> >,
    //...
    public IAlgorithmTemplate<ValueTypeLast, RealWork<ValueTypeLast> > {
};

最后,每个算法都派生自IAlgorithmBase,并将RealWork作为模板实现。

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() {...}
};