2013-11-04 58 views
2

我使用类型擦除设计模式为我的模板类之一公开模板无关的接口。然而,我遇到了这样一个问题,即我希望公开的方法之一,它将两个模板化实例融合到具有不同模板常量参数参数的第三个实例中,似乎需要模板虚拟方法,这是非法的。C++:类型擦除虚拟模板解决方法

这是我的代码:

#include <stdlib.h> 

template<size_t N> 
class bar 
{ 
    template<size_t M> 
    bar<M+N> fuse(const bar<M>& rhs) { return bar<M+N>(); } 
}; 

class bar_any_N 
{ 
private: 
    class abstract_base 
    { 
     virtual bar_any_N fuse(const abstract_base* rhs) = 0; 

     template<size_t M> 
     virtual bar_any_N fuse_accept(const bar<M>& lhs) = 0; 
    }; 

    template<size_t N> 
    class wrapper : public abstract_base 
    { 
    private: 
     bar<N> m_bar; 
    public: 
     wrapper(const bar<N>& the_bar) : m_bar(the_bar) { } 

     bar_any_N fuse(const abstract_base* rhs) { return rhs->fuse_accept(*this); } 

     template<size_t M> 
     bar_any_N fuse_accept(const bar<M>& lhs) { return lhs.m_bar.fuse(this->m_bar) } 
    }; 

    abstract_base* m_ptr; 
public: 
    template<size_t N> 
    bar_any_N(const bar<N>& the_bar) { m_ptr = new wrapper<N>(the_bar); } 

}; 

int main() 
{ 
    bar<1> b1; 
    bar<2> b2; 
    bar_any_N b1_erased(b1); 
    bar_any_N b2_erased(b2); 

    bar_any_N b3 = b1_erased.fuse(b2_erased); 

    return 0; 
} 

没有人有另一种方式来实现这一点,就不需要虚拟模板成员?

编辑:这个“模板独立接口”的目的是为了与不同的模板的参数栏中实例的矢量传递给功能:

std::vector<bar_any_N> vec; 
vec.push_back(bar<2>()); 
vec.push_back(bar<5>()); 
foo_func(vec); 

编辑:

下面是一个更简单的工作示例印刷方法,而不是上面的导火索方法表明我是多么想这个工作:

http://codepad.org/8UbJguCR

+0

'fuse_accept'是否是问题?如果是这样,你为什么不在'abstract_base'中非虚拟地实现它? – LumpN

+1

abstract_base没有(也不能,因为它会强制它被模板化)具有成员m_bar,因此该方法需要是虚拟的才能访问此成员。 –

+0

你究竟是什么意思'模板独立接口' –

回答

2

彻头彻尾的擦除。

struct bar_raw 
{ 
    std::size_t N; 
    explicit bar_raw(std::size_t n):N(n) {} 
    bar_raw fuse(const bar_raw& rhs) { return bar_raw(N+rhs.N); } 
}; 
template<size_t N> 
struct bar: bar_raw 
{ 
    bar():bar_raw(N) {} 
    template<size_t M> 
    bar<M+N> fuse(const bar<M>& rhs) { return bar<M+N>(); } 
}; 

保持所有状态在bar_raw。有一个漂亮的界面,可以帮助编写bar<N>中的代码,如n-ary索引。

当通过bar<N>键入擦除时,您将忽略bar<N>组件,并键入擦除bar_raw,这非常简单。

如果您想要,您可以拨打bar_rawbar_any,或者您可以将bar_raw作为实施细节,并将其包装在bar_any中,这非常漂亮。

+0

以上的保险丝方法)时,我遇到了虚拟模板的这种需要。只需添加我的两分钱:唯一的问题就是整个情况下的类型系统会得到有点混乱和扭曲;如果你想要一致地获取模板化的子类,可以期望执行大量的类型转换或roll-your-own-RTTI。尽管如此,你试图颠覆无虚拟模板的局限性。或者试图将无限变成有限数字。对于编译器来说,这两个问题基本上都是一样的问题。 :-P – user

+0

@Atash这就是为什么我认为'bar_raw'应该是一个私人的细节。类型擦除的案例不能暴露模板化的子类,因为它是类型擦除的。当使用'bar '时,它漂亮的界面会产生一堆类型魔法来产生结果类型,并且它只需要参数'bar '类型,因此它可以在没有任何嘲讽的情况下对这些类型进行数学运算。内部的'bar_raw'最终不得不复制这些工作的大部分,但它管理运行时状态(你证明并声明符合编译时状态)。擦除对象只关心运行时状态。 – Yakk

+0

我想我可能会这样做;然而,有没有人知道是否有替代使用RTTI/dynamic_cast将类型为抽象基指针的类型转换为适当的包装? –