如何转换模板类?

时间:2013-06-21 12:02:34

标签: c++ templates virtual

我有以下示例:

struct Wrapper
{
    virtual ~Wrapper()
    {
    }

    template <typename U>
    WrapperT<U> * clone()
    {
        return new WrapperT<U>(value); //will not work, because value is not known here
    }
};

template <typename T>
struct WrapperT : Wrapper
{
    explicit WrapperT(T v)
    {
        value = v;
    }

    T value;
};

我想要这样的事情:

Wrapper *t = new WrapperT<int>(1);
WrapperT<double> *t2 = t->clone<double>();

我知道虚拟模板不可用。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

一种可能的方法是定义访问者模式,但如果您想支持许多不同的包装类型(即,它不仅仅是一个小子集),实现访问者的成本可能会很高。

你会得到的另一个问题是转换将(必须)动态调度,因此它们可能在运行时失败,你必须提供检测它的机制并对其采取行动(想到异常)。没什么可怕的......

答案 1 :(得分:0)

我建议的解决方案是使用“中性类型”动态制作(如DavidRodríguez - dribeas所说)类型转换。

优势:

  • 解决方案是通用的:使用新类型时,您不需要任何特殊的东西。

缺点

  • 表现不佳。
  • 需要定义插入和提取流运算符。

代码:

struct Wrapper
{
    // get the "neutral type" value
    virtual string getValue() const = 0;

    template <typename U> Wrapper* clone() const;
};

template <typename T>
struct WrapperT: Wrapper
{
    explicit WrapperT(T v):  value(v)
    {
    }

    virtual string getValue() const 
    {
        // use streams to conversion to neutral value, but 
        // other better method would be suitable
        ostringstream   strm;
        strm << value;
        return strm.str();
    }

    T value;
};

template <typename U> Wrapper* Wrapper::clone() const {
    U   value;
    istringstream   strm(getValue());
    strm >> value;

    return new WrapperT<U>(value);
}

修改

要获得更好的效果解决方案,如果只使用数字类型,我们可以将string改为long double作为“中性类型”:

template <typename T>
double long WrapperT<T>::getValue() const 
{
    return value;
}

template <typename U> Wrapper* Wrapper::clone() const {
    return new WrapperT<U>(getValue());
}

当只使用整数类型时,我们是否要避免浮点转换的积分?在这种情况下,解决方案会更复杂一些:

  • 创建两个getValue()虚函数,一个用于积分,另一个用于浮点,
  • clone()函数中,根据getValue()模板参数类型(目标类型)选择所需的U函数。